CREATIVE COMPUTING VOL. 7, NO. 1 / JANUARY 1981 / PAGE 176
The new year brings a lot of promise to Atari owners. We should soon be getting Pascal and a Microsoft Basic, accounting software, and for those of us who prefer to enjoy our computers, a batch of new games. Atari has announced Space Invaders for the 400 and 800 as their first machine language cassette. This game has become one of the most popular arcade and computer games, and I look forward to getting a chance to play it.
We can also expect to see an explosion in Atari software available from sources other than the manufacturer. Just this past October Sensational Software announced Trivia Unlimited, Outdoor Games, Haunted House, Air Traffic Controller, Hail to the Chief, Ecology Simulations I and II, Social and Economic Simulation, Story Time, Oregon Trail, and Stock and Options Trading Analysis. We can only benefit from the wide variety of programs coming out.
There has been a change in the climate for outside software houses in the past year. When appliance type small computers became available, the manufacturers wanted to keep the after market to themselves. In June of 1980 Radio Shack compiled and released through their stores a list of over 1000 programs available from other sources. Exidy and Texas Instuments have been running contests to stimulate software development, with T.I. even sending representatives to most of the major software houses, offering them computers and support in developing software for the 99/4. Apple has cooperated in many ways with software publishers, even allowing mailings to the Apple warranty list.
Atari has been very cooperative from the start. As soon as they knew of outside suppliers they started sending out mimeographed sheets listing programs, prices, and publishers. Recently they invited the sources they knew to submit leaflets for free distribution to the Atari warranty mailing list, and by the time this column comes out many of you should have received the resulting package. If you did not send in your warranty card, you are missing out!
The remainder of this column will be discussing the internal workings of the Atari computer. In order to understand what is happening there, you will need to know a little about the binary number system. If you have a binary brain and already think in ones and zeroes, just skip to the next heading while I attempt to explain the binary system to everyone else.
We human beings tend to think numerically in the decimal system, probably because our ancestors used their fingers as counting tools, and they just happened to have ten fingers. Computers have neither fingers nor our intellectual capacity, so they have to rely on a simpler system. While we have ten different numerals, from 0 to 9, for use in our calculations, the computer can only choose between two states, off or on, for which we use the digits 0 and 1.
To a computer, any given operation usually involves a switch or light that is either on or off, an electrical charge that is either positive or negative, or a magnetic charge that is polarized either ‘north’ or ‘south’.
Let us think about a single digit counter on an assembly line.. If it is a decimal counter, it starts at 0, and when the first object passes, it becomes 1, then 2, and so on until it reaches 9. As the next object passes, the counter goes back to zero. If we wish to continue counting, we need to add another digit, which can count 99 objects, or 100 if you know whether the 00 is the starting position or the ending position.
If the counter is a binary counter, it starts at 0, goes to 1, and then has to reset back to 0 again. If you want to count even as far as 3, you need 2 digits. Where each position in the decimal system represents a power of ten, each position in the binary system represents a power of two. Let us take the number 1 1 1 in both systems as an example. In the decimal system 1 1 1 represents 10 squared, (100) plus 10 to the first power, (10) plus ten to the zero power, (1). The total is one hundred and eleven. Now, let us consider the same group of three digits as a binary number. It now becomes 2 squared, (4) plus 2 to the first power, (2) plus 2 to the zero power, (1). The total is seven. Since we read numbers from left to right, here is a table of the meanings of the positions in a number under the decimal and binary systems:
Number 1 1 1 1 1 1 Decimal 100,000 10,000 1,000 100 10 1 Binary 32 16 8 4 2 1
Using this system, we can now count in the binary system, with the numbers to seven displayed as follows:
Zero 0 0 0 Four 1 0 0 One 0 0 1 Five 1 0 1 Two 0 1 0 Six 1 1 0 Three 0 1 1 Seven 1 1 1
Each digit in the binary system is represented by a single electrical charge in the computer. This is an actual circuit in the computer that has a positive or negative charge. This amount of information is called a Binary digIT, usually referred to as one BIT. Since the central processor on most computers handles eight bits at a time, we also need a term to refer to a group of eight bits, which can give us numbers from zero to two hundred and fifty five. The common term for eight bits is a byte, and the internal memory of the Atari is organized in bytes. Thus, if you have 32K of memory, you have 32,767 bytes of memory, or 262,136 bits. The reason that 32K is 32,767 instead of 32,000 is that we are organized on the binary system, and 32,000 is not an even power of two. The number 32,767 is two to the 14th power. There is one other term that is occasionally used, for a group of four bits. Four bits, or half a byte, is known as a nibble.
Ted Nelson wins my nomination as the most organized editor in computerdom. Way back in September he sent out a list of editorial features for Creative Computing from October 1980 to December 1981. The features scheduled for this month are graphics and animation, digital music techniques, and interactive video disc articles. As a computer addict, I have no money to spare for a video disc, and my musical ability leaves much to be desired. That leaves me with graphics and animation for this column!
The Atari computers have many powerful graphics features, but the better techniques require special knowledge of the hardware and tricky programming. I hope that by giving a sample program and telling how it works, I can open the door to the mysteries and get many of you started.
Let me begin by acknowledging a great deal of help from Atari, especially from Lane Winner, who gave me the sample program presented here and explained it, and to others on the staff who provided me with well over 1000 pages of documentation, preliminary manuals, printouts, programs, and even memos explaining the working of the computer. I also need to credit Rich Bouchard, SoftSide’s brilliant systems programmer, for converting all my hexadecimal addresses to decimal for your benefit. I must confess that I tend to think in hexadecimal.
100 DIM A$(10),B$(100) 200 GRAPHICS 8 210 POKE 559,62 220 POKE 53246,120 230 POKE 704,88 240 I=PEEK(106)-8 250 POKE 54279,I 260 POKE 53277,3 270 POKE 53256,3 280 J=I*256+1024 300 FOR Y=J+120 TO J+137 310 READ Z 320 POKE Y,Z 330 NEXT Y 400 FOR X=48 TO 221:GOSUB 500:NEXT X 410 GOTO 400 500 POKE 53248, X 510 RETURN 600 DATA 60,60,60,60,60,60,255,255,255,255,255,255,60,60,60,60,60,60
Line 210 specifies the regular playfield in single line format as a background, from six possible options.
Codes: 61 narrow field (128 dots) 62 regular field (160 dots) 63 large playfield (goes off screen) 45 double line narrow playfield 46 double line regular playfield 47 double line large playfield
Line 220 tells the horizontal position register to put player at mid screen (location 120). The regular playfield ranges from 48 to 221. The horizontal position registers are at the following locations in memory:
Player 0 53248 Player 1 53249 Player 2 53250 Player 3 53251 Missile 0 53252 Missile 1 53253 Missile 2 53254 Missile 3 53255
It is possible to combine the 4 missiles into a fifth player.
Line 230 sets the color of Player and Missile to Pink. You can write directly into the color registers starting at 704, or indirectly through the hardware chip starting at location 53266.
Chart of Color Locations Player/Missile 0 704 or 53266 Player/Missile 1 705 or 53267 Player/Missile 2 706 or 53268 Player/Missile 3 707 or 53269 Playfield 0 708 or 53270 Playfield 1 709 or 53271 Playfield 2 710 or 53272 Playfield 3 711 or 53273 Background 712 or 53274
Understanding the color system reguires binary arithmetic. The least significant bit of the color byte is not used, and is identified with an x in the diagrams. Bits 1 to 3 carry the luminance, from black (0 0 0 x) to white (1 1 1 x). Bits 4 to 7 contain the color, as follows: (b represents the luminance bits)
Grey ( 0 0 0 0 b b b x ) Gold ( 0 0 0 1 b b b x ) Orange ( 0 0 1 0 b b b x ) Red Orange ( 0 0 1 1 b b b x ) Pink ( 0 1 0 0 b b b x ) Purple ( 0 1 0 1 b b b x ) Purple Blue ( 0 1 1 0 b b b x ) Blue ( 0 1 1 1 b b b x ) Blue ( 1 0 0 0 b b b x ) Light Blue ( 1 0 0 1 b b b x ) Turquoise ( 1 0 1 0 b b b x ) Green Blue ( 1 0 1 1 b b b x ) Green ( 1 1 0 0 b b b x ) Yellow Green ( 1 1 0 1 b b b x ) Orange Green ( 1 1 1 0 b b b x ) Light Orange ( 1 1 1 1 b b b x )
Line 240 looks at the pointer to the top of memory. The top of memory is identified by 256 byte ‘pages’. Thus, if this location had the number 100 (decimal), the top of memory would be at byte 25,600 (256 times 100). We subtract 8 from this number, because we want to save 8 pages (2048 bytes) for our graphics at the top of memory.
Line 250 places the address calculated above as the beginning of our graphics area in the Player/Missile Base Address Register which is at location 54279.
Line 260 tells the Graphics control register to enable player missile graphics. Only the three least significant bits of this register are active, as follows:
( x x x x x x x 0 ) Player missile graphics not enabled ( x x x x x x x 1 ) Player missile graphics enabled ( x x x x x x 0 x ) Direct memory access to player graphics disabled ( x x x x x x 1 x ) Direct memory access to player graphics enabled ( x x x x x 0 x x ) Trigger latches disabled ( x x x x x 1 x x ) Trigger latches enabled
Note that once direct memory access is enabled, it continues until it is disabled again. If you press break and list this program, you will see the player as a moving vertical line on the screen. To return to a normal display, you must type POKE 53277, 0.
Line 270 sets the size register for Player to four times normal size. Each player or missile can be the full height of the screen. Actually, they extend beyond the top and bottom. But players can only be 8 bits wide, and missiles 2 bits wide. There are dedicated microprocessor chips in the Atari computers to control these players and missiles. We change the size with a POKE into the size registers at the following locations.
Player 0 size 53256 Player 1 size 53257 Player 2 size 53258 Player 3 size 53259 Size for all missiles 53260
The following values are allowed. Only the two least significant bits are used for the player registers. The missile register is grouped so that each two bits represent a different missile.
Value Result 0 or 2 Normal size 1 Twice normal size 3 Four times normal size
Line 280 points to a memory location 1024 bytes (1K) after the beginning of the Player Missile Base address we established in lines 240 and 250 for our binary description of player 0. Remember that the player can extend from beyond the top of the screen to below the bottom of the screen. Actually, 256 bytes of information are reserved for player 0, beginning 1024 bytes past our base address.
We now need a memory map of the Player Missile bit map area. Actually, there are two possible memory configurations, depending upon the value in location 559 (see the explanation for line 210 above). If we have single line graphics, with 61, 62, or 63 in location 559, then the memory is used as follows:
Offset from Base Address Use 0 - 767 Not used 768 - 1023 Missiles 0 - 3 1024 - 1279 Player 0 1280 - 1535 Player 1 1536 - 1791 Player 2 1792 - 2047 Player 3
If double line graphics are used, with 45, 46, or 47 in location 559, you only need 1K, or 4 pages of memory, (see below for program changes.) Then the offset is as follows:
Offset from Base Address Use 0 - 363 Not used 384 - 511 Missiles 0 - 3 512 - 639 Player 0 640 - 767 Player 1 768 - 895 Player 2 896 - 1023 Player 3
Note that the missiles are stored in memory as a single player. When you are using missiles and drawing your bit map. Missile 0 is bits 0 and 1 of each byte. Missile 1 is bits 2 and 3, Missile 2 is bits 4 and 5, and Missile 3 is bits 6 and 7.
Line 300 selects the memory location for our bit map. We are only going to draw a character 18 bytes high, at about the middle of the screen, so we will leave most of player in the background color, and place information on our character in locations 120 to 137 of the memory reserved for player 0.
In lines 310 and 330, we read our binary shapes from data into the appropriate locations in player zero’s reserved memory. Each number is a ‘bit map’ of a horizontal slice of player 0, eight bits or one byte wide. Thus the number 60 represents the binary pattern 00111100. Each bit that is zero represents one location on the screen that is presented in the background color, while each one represents a memory location presented in the color set for player 0.
I selected a simple cross for demonstration program just to illustrate the principle. Here is a bit map of player zero:
Locations Decimal Bit map 0 - 119 0 0 0 0 0 0 0 0 0 120 - 125 60 0 0 1 1 1 1 0 0 126 - 129 255 1 1 1 1 1 1 1 1 130 - 135 60 0 0 1 1 1 1 0 0 136 - 255 0 0 0 0 0 0 0 0 0
To create your own players, just map out the bits and convert them into decimal numbers, then POKE them into the display list.
Lines 400 and 410 contain the horizontal positions for our player, and control its movement across the screen. Location 48 is the left edge of the screen and location 221 is the right edge.
Line 500 POKEs the desired horizontal position of player into the position register for player 0. Here is a chart of the memory locations for the horizontal position registers:
Player/Missile Register Player 0 53248 Player 1 53249 Player 2 53250 Player 3 53251 Missile 0 53252 Missile 1 53253 Missile 2 53254 Missile 3 53255
Line 600 contains data for the shape of our player, as described above in the description of lines 300 and 310.
If you are going to experiment with this program, I suggest that you add the following line:
340 PRINT "POKE 53277,0 : GR.0 : LIST"
This way, in order to change the program, all you have to do is press BREAK, move the cursor on top of the statement on the bottom of the screen, and press ENTER to turn off the direct memory access and list your program.
Use these changes to try double line graphics:
210 POKE 559,46 240 I=PEEK(106)-4 280 J=I*256+512 300 FOR Y=J+60 TO J+77
These changes specify a double line regular playfield, reserve only one page of memory instead of two, and adjust the bit map for the more compact memory storage.
Have fun playing with this information, and share your discoveries with me. The quickest way to reach me is at my home address listed at the bottom of the first page of each month’s column. Letters sent through Creative Computing, The Boston Computer Society, SoftSide, Ramware, or The Software Exchange take extra handling and extra time. I regret that it is not possible for me to talk to you on the telephone or answer correspondence except through the column.
CREATIVE COMPUTING VOL. 7, NO. 2 / FEBRUARY 1981 / PAGE 168
This month I can’t even see out the windows of the outpost. The whole station is filled with mail! Back in November I reported on an article that was scheduled to appear in Byte in August. The author had described it to me and Byte was kind enough to give me an advance look. Unfortunately, Byte rescheduled the article, and the post office and telephone company made a killing. I have been receiving several letters and phone calls a day asking where to find the Byte article, which describes how to modify the display list for fancy graphics. At a seminar in New York City in November, Chris Morgan told me the article had been rescheduled for January, but there is no guarantee that it is in that issue.
While we try to make our columns timely (Happy Valentines Day!), it takes over two months to prepare an article for publication, put a magazine together, have it printed, and deliver it through the mail. That means that by the time you read this issue, I will be working on the May column. Although columns are usually regular, there are many things that may cause an article to be postponed to a later issue or even dropped altogether. Usually an editor will try to create the best possible mixture of articles in a given issue right up to the last possible moment. I have seen articles changed even after getting the proofs from the printer.
In the listing of the error trapping routine in November, submitted by Larry Seftor, one line of the listing was transposed. The “* 256+PEEK(186)” should be at the end of line 1010, not the end of 1000.
Walter Knoch, of Boca Raton, Florida, sent in this interesting graphics program. It demonstrates an effective use of color changes.
10 GRAPHICS 23:DEG:SETCOLOR 2,4,10:DIM C(3) 20 R=20:COLOR 1:C=1 30 X0=79:Y0=47 40 FOR K=0 TO 3:C(K)=K+1*2:NEXT K 50 FOR K=1 TO 3 60 X=X0+R*COS(360) :Y=Y0: PLOT X,Y 70 FOR I=0 TO 5*360 STEP 75 80 X=X0+R*COS(I) : Y=Y0+R*SIN(I) 90 DRAWTO X,Y 100 NEXT I:R=R+12:C=C+1:COLOR C 110 NEXT K 120 FOR I=0 TO 2: SETCOLOR I,C(1),10 :NEXT I 130 FOR J=1 TO 100 : NEXT J 140 FOR I=1 TO 3: C(I-1)=C(I) :NEXT I 150 C(2)=RND(1)*16 : GOTO 120
At the Boston Computer Show, dressed in a black cape and wizard’s cap, Russ Walter was selling copies of his series of books, The Secret Guide to Basic. As I paused to greet him, he thrust a fluorescent pink book into my hands and proclaimed, “Its about time for me to give you something else!”
The title of the book was Hassles in Basic, volume 2 of the series. The subject is converting programs from one Basic to another, and the Atari is one of the principal systems covered, along with the TRS-80, Apple, and PET. He also occasionally mentions a bunch of obscure computers I never heard of, with weird names like PDP-11 and IBM.
The book has brief, easy to understand explanations of most of the problems involved in conversion, giving attention to graphics, music, tricky functions, style, and even speed. There is even a page with genuine English language explanations of the most frequent Atari error codes!
The Secret Guide to Basic is an excellent series, and I especially endorse this volume. Russ sells them for the ridiculously low price of $3.70 each, and even pays the postage. Order from Russ Walter, 92 St. Botolph St., Boston, MA 02116.
Since so many of you have expressed an inordinate curiosity about the inner working of the Atari, I will devote more attention to it. First, here are three programs to help you discover what’s going on in there. All display memory, the first one in decimal, the second in hexadecimal, the last in ASCII characters. I deliberately kept them short, so you can type them into other programs to look at the display lists and other mysteries.
If you are using these programs within your other programs, you will want to use different line numbers, eliminate remarks and most print statements, abbreviate statements, and use multiple statements per line. If you are just looking at memory, you may want to add features, combine all three into one program, and expand such conveniences as the pause feature in lines 5, 12, 13, and 14 of the Hex Dump routine. If you want to experiment by writing directly into memory locations to see what happens, use a routine such as this one.
1 REM * MEMORY MODIFICATION * 2 INPUT S 3 PRINT S,: INPUT C 4 POKE S,C : S=S+1 : GOTO 3
Not that you have the tools for peeking and poking around in memory, what can you find there? Last month’s column discussed how to use these locations:
240 This sets the page number for the top of memory.
1 REM * DECIMAL DUMP * 2 PRINT"START";: INPUT S 3 PRINT S,PEEK(S):S=S+1:GOTO 3 (You have to press BREAK to stop the decimal or the ASCII dump.) 1 REM * HEX MEMORY DUMP * 2 GR.0:DIM H$(16) 3 H$="0123456789ABCDEF" 4 PRINT"STARTING ADDRESS (DECIMAL) ";: INPUT S 5 PRINT"HOLD SPACE BAR TO STOP" 6 PRINT S;" "; 7 FOR M=S TO S+7 8 H=PEEK(M) :L=INT(H/16):R=H-L*16 9 L=L+1:R=R+1:PRINT H$(L,L);H$(R,R);" "; 10 NEXT M:PRINT 11 S=S+8 12 IF PEEK(764)>254 THEN 6 13 PRINT" (1 - CONTINUE 2 - STOP) " ; : INPUTH 14 IFH=1THEN6 1 REM * ASCII DUMP * 2 INPUT S 3 PRINT S;" "; 4 FOR M=S TO S+9 5 A=PEEK(M) 6 IF A>26 AND A<30 THEN 11 7 IF A>124 AND A<128 THEN 11 8 IF A>154 AND A<160 THEN 11 9 IF A>252 THEN 11 10 PRINT CHR$(A);" ";:GOTO 12 11 PRINT". "; 12 NEXT M : PRINT : PRINT : S=S+10 : GOTO 3
559 This sets the playfield size.
704-712 These are the “shadow” registers for the player missile color registers at
53266 to 53276. You can write directly to the ANTIC chip or to the shadow register.
54279 This is the player/missile base address register which holds the page number of the beginning of the player missile graphics area.
In addition to these locations, Appendix I of the Basic Reference manual lists a few more. Whenever you have a two byte address register, multiply the contents of the second address by 256 and add the contents of the first address. Thus, to find the highest memory location used by Basic, use this line:
PRINT PEEK(14) + 256 * PEEK(15)
Now for the special effects! Here are descriptions of the effects of the CTIA chip and its memory locations. Since the chips behave differently depending whether you are writing (POKE) to the address given or reading (PEEK) it, I will explain first what happens when you write, then when you read the memory location.
53248 to 53255 These are the horizontal position registers explained last month.
53256 to 53269 These are the size registers discussed last month.
53260 (Player 0) to 53264 (Player 3) and
53265 (All missiles) These addresses write directly into the player graphics registers without going through direct memory addressing.
53266 to 53274 These are the color registers discussed last month.
53275 This is the priority control register. Bits through 3 select the priority of the different players, so that the player with the highest priority will appear to be in front of the player with the lower priority. Setting a bit to true (1) establishes priority. If more than one bit is true, the playfield will be black when those players overlap. Here is the table of priorities for the different bits. The highest priority is at the top of the list.
Bit 0 = 1 Bit 1 = 1 --------- --------- Player 0 Player 0 Player 1 Player 1 Player 2 Playfield 0 Player 3 Playfield 1 Playfield 0 Playfield 2 Playfield 1 Pf 3 & Pl 5 Playfield 2 Player 2 Pf 3 & Pl 5 Player 3 Background Background Bit 2 = 1 Bit 3 = 1 --------- --------- Playfield 0 Playfield 0 Playfield 1 Playfield 1 Playfield 2 Player 0 Pf 3 & Pl 5 Player 1 Player 0 Player 2 Player 1 Player 3 Player 2 Playfield Player 3 Pf 3 & Pl 5 Background Background
Bit 4 enables the fifth player by causing all missiles to assume the color of playfield 3. That is why playfield 3 and player 5 are combined in the chart above.
Bit 5 enables a logical OR function for the colors of player with player 1 and player 2 with player 3, enabling a choice of three colors when they overlap.
53276 This is the vertical delay register. By writing to this register, you can move objects down the screen by one TV line in the two line direct memory access mode. Bits 0 to 3 control missiles to 3 and bits 4 to 7 control players to 3. For example, writing a 1 to bit 3 with a POKE 53276,8 will cause missile 3 to drop one line.
53277 This is the graphics control register discussed last month.
53278 This write address resets all the collision registers after you have read them to determine collisions so that you can continue on the next cycle. The collision registers are explained below.
53279 Writing a zero to this address resets the console switches. See the read table below for an explanation of the switches.
53248 to 53263 are addresses that you can read to determine collisions between players, missiles, and playfields. In each case, the first object given is the one being read. The second object is the type of object being checked. Bit 0 to 3 indicate the number of the colliding object. For example, if Missile 0 collides with playfield 2, Bit 2 of location 53248 will contain a 1, and PEEK(53248) is equal to 4. Only the four least significant bits of each address are used, with the high bits always zero. In addition, on player to player registers, player to player will always read zero, as will each of the others when compared to itself.
Primary Objects Address Object tested (0-3) 53248 Missile 0 Playfields 53249 Missile 1 etc. 53252 Player 0 Playfields 53253 Player 1 etc. 53256 Missile 0 Players 53257 Missile 1 etc. 53260 Player 0 Players 53261 Player 1 etc. 53263 Player 3 Players
The other objects can be interpolated from those given.
53264 to 53267 are the controller trigger latches. When the trigger is pressed, bit of the appropriate latch goes to 0. All the other bits are forced to at all times. Bit 2 of the graphics control register at 53277 controls these, as described last month. If it is 1, the inputs are latched when they go to zero. If bit 2 of the graphics control register is set to 0, these latches are reset to 1, (Note: the term “latched” means that a computer memory location is locked in one state, and held until it is changed deliberately.)
53264 Trigger 53265 Trigger 53266 Trigger 53267 Trigger
53268 to 53278 do not have separate functions as read addresses. See the write descriptions above.
53279 is the console switch register. Bits 3 to 7 are forced to 0, and are not used. Bits to 2 correspond to the console switches as follows:
Bit 0 Game Start Bit 1 Game Select Bit 2 Option Select
These bits are normally ones, but become zero while the switch is held down. Thus PEEK(53279) is usually 7, but becomes 3 when the option select button is pressed.
In future columns 1 hope to experiment with the ANTIC and POKEY chips. The PIA chip was explained in the October 1979 column in the section on Input and Output with the light sensor. The program in Figure 2 of that column demonstrates the PIA.
My first computer language was 6800 assembly language, which I learned with Heathkits ET 3400 Microprocessor Trainer and ET 3401 Microprocessor self instruction program. This course teaches both hardware and software concepts, and the hardware section requires a good background in electronics, so I have hesitated to recommend it to the average person in the past. Heath has now taken the software portion of that course and packaged it separately, and also provided a less expensive trainer. The course has part number EC 6800, and the trainer is part number ET 6800.
Once you have a good understanding of assembly language, it is easy to switch from one chip to another, and the 6800 is fairly close to the 6502, so do not let the different chip stop you. Perhaps one of you readers could write a 6800 emulator for the Atari, and save others the $130 cost of the trainer. The course itself sells for $29.95, and I consider it the best way I have yet seen to learn assembly language.
For you aliens (owners of non-Atari computers) reading this column. Heath also has a course in 8080 and 8085 assembly language for $49.95. 1 have built a number of Heathkits, and taken several of their courses, and I feel they have always given me my money’s worth. The only complaint I have had is that every kit including integrated circuits has had bad ones, but Heath is good about replacing defective parts.
If you haven’t mastered Basic, you may not like me dwelling on assembly language. I feel that this course is good preparation for learning Basic. Six months after completing the Heathkit course, I bought a TRS-80 and learned Basic in one week using David Lien’s Learning Level I. It was very easy to leam because the Heath course gave a good understanding of the internal workings of the computer.
Right now the Atari computers give owners the easiest route to publishing success. It is obviously coming on strong as the best of the current personal computers, and it is being supported strongly by several magazines and software publishers. However, there are not as many owners as there are for the antiquated TRS-80s and Apples, so good articles and programs are easy to sell.
Do your part to support the Atari. The more articles and software that is available, the more people will buy the Atari. That in turn will make more and better programs available for all Atari owners. Don’t forget Creative Computing and Sensational Software when you are seeking a publisher.
CREATIVE COMPUTING VOL. 7, NO. 4 / APRIL 1981 / PAGE 194
This month’s column may be heavy going for beginning programmers. I apologize for that, but my mail has contained many requests for a description of the special graphics features of the Atari computers and I need all of this month’s space. Unfortunately, we need more subscribers interested in the Atari to justify a large Atari column. Most of you will want to save this material for future reference, even if you cannot use it yet.
The long awaited complete information on the operating system is finally ready, and can be ordered by sending $30 to Atari Inc., Operating System Manual. Attn. Tom Harris, 1346 Bordeaux Avenue, Sunnyvale, CA 94082. The manual goes beyond the material I covered in the last three columns and contains over 200 pages of technical material. It is not elementary reading.
Back in January’s column we experimented with a program to move player missile graphics horizontally across the screen. That was the easy part. Much more difficult is vertical motion. We could move small figures simply by PEEKing each byte and POKEing it into the next memory location, but that is a slow process and it is hard to do it between television refresh cycles for smooth motion. Instead we have chosen to fool the computer into thinking that the display area for Player is a string variable, so that we can use Basic’s machine language string movement routines to move our player around in memory.
In order to understand how to do this, it is necessary to know how Atari Basic stores variables in memory. Two areas are set aside in memory. The first, the Variable Value Table, stores 8 bytes of information on each variable declared in your Basic program. The second, the String Array Table, reserves space in memory according to the size specified when you dimension an array. For example, the very first command in our program, DIM P$(1), sets up information in the Variable Value table to tell us that string array variable number has one byte of storage reserved and bytes in use, and reserves one byte of memory in the array area to store the contents of P$.
Memory locations 134 and 135 store the location in memory of the variable value table, which we can find by multiplying the contents of location 135 by 256 and adding the contents of location 134. The first of the eight bytes reserved for each variable tells what kind of variable it is, whether scalar, array, or string. If it is a scalar variable, this byte is 0. If it is an array variable, bit 6 is set, and if it is a string variable, bit 7 is set. In addition, if an array variable is properly dimensioned bit is set. We therefore should find this location to contain decimal values of for scalar variables. 65 for properly dimensioned array variables, and 129 for properly dimensioned string variables. The second byte is the variable number, in order from 0 to 127. Since they are in order and in sequence, this is simply wasted memory. The other six bytes vary according to the type of variable.
Here is our January program modified to demonstrate vertical motion of player number 0:
Listing number ONE 100 DIM P$(1),B$(18),D$(18) 110 B$="(Put 18 hearts here using CONTROL COMMA)" 120 VTAB=PEEK(134)+256*PEEK(135) 130 ATAB=PEEK(140)+256*PEEK(141) 200 GRAPHICS 8 210 POKE 559,62 : REM REGULAR PLAYFIELD 230 POKE 704,88 : REM PLAYER - PINK 240 PMBASE=PEEK(106)-8 : REM TOP OF MEMORY 250 POKE 54279,PMBASE 260 POKE 53277,3 : REM ENABLE DIRECT MEMORY ACCESS 270 POKE 53256,3 : REM PLAYER 0 = 4 X NORMAL SIZE 280 PM0=PMBASE*256+1024+236 300 FOR Y=PM0 TO PM0+17 310 READ Z 320 POKE Y,Z 330 NEXT Y 340 POKE 53248,100 : REM INITIAL HORIZONTAL POSITION 400 DATA 60,60,60,60,60,60 410 DATA 255,255,255,255,255,255 420 DATA 60,60,60,60,60,60 500 OFFSET=256 * PMBASE + 1024 - ATAB 510 V3=INT(OFFSET/256) 520 V2=OFFSET-256*V3 530 POKE VTAB+2,V2 : REM NEW LOCATION OF P$ DATA 540 POKE VTAB+3,V3 550 POKE VTAB+4,20 : REM SET P$ LENGTH TO 276 BYTES 560 POKE VTAB+5,1 : REM (1 * 256 + 20 = 276) 570 POKE VTAB+6,20 : REM BYTES IN USE = 276 580 POKE VTAB+7,1 590 D$(1,18)=P$(236,253) : REM PUT DRAWING IN D$ 600 FOR X=236 TO 1 STEP -1 610 P$(X,X+17)=D$ 620 P$(X+18,X+35)=B$ 630 NEXT X 700 FOR X=20 TO 200 710 P$(X-18, X-1)=B$ 720 POKE 53248, X 730 P$(X,X+17)=D$ 740 NEXT X 800 POKE 53248,1 : REM MOVE HORIZONTAL POSITION OFF SCREEN 810 POKE 53277,0 : REM TURN OFF DIRECT MEMORY ACCESS
I will not explain lines 200 through 420, as they have already been covered in January’s column. The rest of the lines are explained in order.
There you have it. High speed independent character motion from Basic. All you have to do is build on this and use the priority schedule and collision registers explained in last month’s column, and you can do graphics with your Atari beyond the ability of any other small computer.
In the February column we discussed the many functions of the CTIA dedicated microprocessor chip in the Atari computers. This month we will cover the ANTIC chip, another dedicated chip located in memory at D400 to D40E (54272 to 54287 decimal).
Listing number TWO 0 = Turn of direct memory access display. Bits 1 and 0 0 1 Narrow Playfield (Width - 12B) 1 0 Standard Playfield (Width - 160) 1 1 Wide Playfield (Width - 192) Bit 2 = 1 Enable direct memory access for missiles. Bit 3 = 1 Enable direct memory access for players. Bit 4 = 1 Single line resolution for players. Bit 5 = 1 Direct memory access enable for instruction fetch.
Listing number THREE Bit 0 = 1 Invert line of characters. (following for 40 character mode only) Bit 1 = 1 If Bit 7 of character code is 1, print character black on white. Bit 2 = 1 If Bit 7 of character code is 1, blink that character.
This is presented least significant bit first, then most significant bit. The display list is a sequence of one or three byte display instructions in memory. Each instruction can display one to sixteen lines of data on the screen. The single byte instructions consist of an opcode, while the three byte instructions consist of an opcode and an address. This address can be, depending on the opcode, the address in memory of data to be displayed directly, the address in memory of character data to be displayed indirectly, or a jump. If it is a jump, the address is loaded into the display list counter. Otherwise the address is loaded into the memory scan counter. In the case of single byte opcodes, memory is displayed beginning at the present location of the memory scan counter.
A full explanation of the memory map and character displays is too long for this column. I have asked a guest columnist to explain the display list in the June column.
These registers are triggered by flag bits in the instructions from the display list. Bit 4 of the display list instruction is a horizontal flag bit and bit 5 is a vertical flag bit. A one in the flag bit activates the scroll register, rotating the display right or up from 0 to 15 locations according to the number in bits 0 to 3 of the scroll register.
We used the first of these registers in line 250 of our demonstration program to establish a location for our display data. For an explanation of how this memory is organized, see my January column, page 179. The character register works with character data in graphic modes - 2.
The Player Missile Base register and location 54278 can also be used in 2 line resolution modes as a player missile scan counter (bits to 6), player missile select register (bit 7), and using bits 10 to 15 as the address register.
The character register can also be used in conjunction with 54280, using bits to 2 to indicate the character line and bits 3 to 8 for the character name. Bits 9 to 15 then become the base register.
Writing to this address sets a memory latch that pulls the READY line on the microprocessor low, causing output to stop until the next horizontal blank on the screen automatically resets the latch.
A zero in this location disables the interrupts, except the RESET button, which is always enabled. Only bits 6 and 7 are used. If bit 6 is a 1, the vertical blank interrupt is enabled, and if bit 7 is a 1, the display list instruction interrupt is enabled.
This register identifies the causes of interrupts. Bit 5 indicates that the RESET button was pushed. Bit 6 indicates an interrupt caused by the beginning of a vertical blank. Bit 7 identifies a display list instruction interrupt. Write a zero to this location to reset this register.
These addresses identify the contents of the light pen registers.
This location points to the current vertical line. This register is somewhat tricky, as it does not simply give the line number, and can count singly or doubly.
CREATIVE COMPUTING VOL. 7, NO. 5 / MAY 1981 / PAGE 210
The guest author for this column is Mike Dunn, a busy pediatrician, who, among his many other hobbies, became enchanted with the Atari 800, started a newsletter, and is now preparing his first program for possible commercial release.
One of the nicest features of the Atari is its toll-free Help line. First try to figure it out yourself, as you will learn more, but if you can’t, call Atari. The “Dear Abby” is Pam Yokum of Programming Services, always helpful on the phone, and, if she doesn’t know the answer, will find out and call or write you with it. The telephone number is (800) 538-8547, except in California, where you call (800) 672- 1 404. If you would like to know everything about your Atari, what each chip does and how you can make it do it, as well as the schematics and all the other “secrets” of this amazing computer, send $30 to Atari. Attn: Tom Harris. Customer Services. 1265 Borregas Ave.. Sunnyvale. CA 94086 for a huge book, many hundreds of pages long, clearly written, and very interesting. Ask for the Operating System and Hardware manuals.
One of the unfortunate results of being involved with a computer is that you quickly discover that a computer can be as useful as the advertisements slate. Mailing lists, database programs, word processing, and. especially. Visi-Calc are as useful as they say, taking time away from the “fun” side of computing.
VisiCalc is something else! After trying, without much success, to convince my partners that we needed to make some changes in our clinic. I had almost given up. One week after receiving VisiCalc. I put our entire operation on it, and in a two-day conference, used the “what-if” feature to show what these changes would mean to each person’s income. The changes were adopted unanimously, more than making up for the cost of my entire computer system. Enough story telling: on with some hints and programs that should make your Atari more useful and fun.
How would you like to listen to your Atari through your stereo system? It is especially impressive with the Music Editor (an excellent cartridge with which to learn music), or Star Raiders (for realistic sounds of the battle). It is easy to do if you know how to solder at all. On the side of the Atari by the ON switch is the video monitor jack. A 5-pin DIN plug to fit this is readily available at any electronic parts store. Counting counter-clockwise from the bottom five pins, you connect the shielded “mike” wire to pin 1 and the shield to pin 3. For mono, the other end is attached to an RCA-type plug, or for stereo, split into 2 and connected to the Stero. If your stereo has a mono switch, only the mono setup is needed. (See Diagram 1.)
The Atari does not have string arrays. However, it does have numerical arrays, as well as an unusual feature that Microsoft Basic does not have, that is, variable names can be used in GOTO and GOSUB statements. These variables can be used in many ways, including simulating “string arrays” in a way I have not seen described before. (See Listing 1.)
As far as I can tell, this “string array” works just like that of other Basics. Using variable names with GOTO and GOSUB is useful in joystick controls, using the number generated by the STICK(N) command to go to a subroute.
Listing 1. 10 DIM A(4),A$(30) 20 X=INT(RND(0)*4) 30 A(0)=1000 40 A(1)=1001 50 A(2)=1002 60 A(3)=1003 70 GOSUB A(X) 80 PRINT A$ 100 END 1000 A$="MONSTER":RETURN 1001 A$="DOG":RETURN 1002 A$="BIRD FROM THE SKY":RETURN 1003 A$="MAN":RETURN
There are several menu programs in circulation, but they tend to be long and slow. These menus list to the screen the disk directory, so you can pick your program. The program in (Listing 2) is a very quickly loaded and run program for that purpose, and is especially useful for DOS II, as the new DOS is loaded in two parts. The new DOS takes only 3K of memory compared to the old DOS, which takes 8K, but the disk directory is loaded on demand, taking some time. Notice line 20, using wild cards to load every filename, and line 50, using the 6 command, a special input command that calls only the disc directory. Line 60 uses an error message 136 (EOF) to indicate that the input is finished, and directs the program to line 90, closing the #1 file, always close the open files with a CLOSE, END, or RUN command, or all kinds of strange bugs will occur in your program, especially when using disc files and the printer. The use of an error TRAP is handy to direct the program to a CLOSE statement.
Listing 2. 1 POKE 82,0:POKE 83,40 10 GRAPHICS 0 13 DIM FILE$(30) 20 FILE$="D:*.*" 50 OPEN #1,6,0,FILE$ 55 OPEN #2,8,0,"E:" 60 TRAP 90:INPUT #1;FILE$ 70 PRINT #2;FILE$ 80 GOTO 60 90 CLOSE #1 100 ?:?:?" TYPE RUN "D:NAME TO ENTER PROGRAM"
Program 3 is a similar program, but is intended to be a subroute for another program to list the disk directory, as in Database where you would like to know what programs are stored on the disk. Note line 10000 and 19999. In line 10030,a comma after “C$” indicates a TAB, so two columns of names are printed on the screen. In the default mode of the Atari, the screen is 38 charactors wide, which causes the columns of words to print on the screen diagonally. The poke statements first change the screen width to 40 characters, allowing the columns to line up, then return to the default mode of 38.
Listing 3 10000 ? :POKE 82,0:POKE 83,40 10001 DIM Z$(15),C$(25) 10005 Z$="D:*.*" 10010 CLOSE #1:OPEN #1,6,0,Z$ 10015 Z=1 10020 TRAP 1999:INPUT #1,C$ 10030 PRINT C$, 10040 Z=Z+1 10050 GOTO 10020 19999 CLOSE #1:POKE 82,2:POKE 83,38:TRAP 40000 20000 RETURN
Here is a handy program (see Listing 4) that will turn your Atari and printer into an “intelligent” electric typewriter. You simply type in your text a printer line width at a time, and when you press RETURN, the line is printed just like an electric typewriter!
You can edit your line before printing by using the cursor as an editor. When it is not necessary to save a program, this is a very easy way to print and edit, especially for a poor typist who makes lots of mistakes. Note line 10, the 12 command that makes the screen editor an input and output device at the same time.
Listing 4. 1 DIM A$(256) 10 OPEN #1,12,0,"E:" 15 OPEN #2,3,0,"P:" 20 INPUT #1,A$ 30 PRINT #2,A$ 40 GOTO 20
The next program (Listing 5) illustrates how to make and change disk data files, and the different modes used. On line 10, we create a string, WORDS, in which to store our data. Line 20 uses the mode 1 2 to both input and output to and from the screen editor, using the cursor to input data, as mentioned above. Line 30 opens a disk file with mode 8, the output mode. To intialize a disk file, this mode must be used. On line 40, we input from the screen editor by typing in our words, remembering that the Atari operating system will allow only three physical lines without entering a RETURN; the computer will remind you with a “beep” at the end of the third line. When a file, especially a disk file, is opened it must be closed to be entered and completed. The TRAP 100 directs the program to line 200 with an error message. To generate the error message, press control-3, making an automatic error-136 (End of File) message. Line 50 prints to device #2, in this case the disk file, the words inputted from the screen editor above, and line 70 goes back to get the next line until the file is ended by your control-3 trap. The STOP is there so you can see what each mode does; use CONT to continue to the next step.
Line 200 opens the diskfile to input with mode 4, and the error message for the End of File trap is generated by the computer when the entire file is read.
Line 320 opens a file already existing and allows you to add to the file. If mode 8 is used, the existing file is destroyed in making the new one, but in mode 9, it is not, so you can add to the file, without loading to the screen editor first.
These programs illustrate how to use the different modes Input and Output commands. There are actually many more I/O commands using the XIO statement, that allow even more flexibility. The Atari Basic Reference Manual describes 16 such commands, and the Atari 850 Interface Manual has many more, used mostly to configure the various I/O ports for any possible use.
Listing 5. 1 REM CREATE FILE 10 DIM WORD$(256) 20 OPEN #1,12,0,"E:" 30 OPEN #2,8,0,"D:TEST1" 40 TRAP 100:INPUT #1;WORD$ 50 PRINT #2;WORD$ 70 GOTO 40 100 CLOSE #2:STOP 199 REM READ FILE 200 OPEN #2,4,0,"D:TEST" 210 TRAP 250:INPUT #2;WORD$ 220 PRINT #1;WORD$ 230 GOTO 210 250 CLOSE #2:STOP 299 REM APPEND (ADD TO FILE ABOVE)-NEW WORDS AFTER OLDFILE 310 CLOSE #1:OPEN #1,12,0,"E:" 320 OPEN #2,9,0, "D:TEST" 330 TRAP 390:INPUT #1;WORD$ 340 PRINT #2;WORD$ 350 GOTO 330 360 CLOSE #2:STOP 399 REM APPEND- NEW WORDS BEFORE ABOVE OLDFILE 420 OPEN #2,12,10,"D:TEST" 430 TRAP 490:INPUT #1;WORD$ 440 PRINT #2;WORD$ 450 GOTO 330 490 CLOSE #2:STOP
CREATIVE COMPUTING VOL. 7, NO. 6 / JUNE 1981 / PAGE 210
The Atari computer is rapidly becoming one of the most popular home computers because of its advanced video capabilities. With the new business programs that are being released by Atari and third-party vendors, the neophyte computer enthusiast who wants a machine that can balance his checkbook and inventory his stock may now look more favorably at the Atari line than in the past.
No home computer has the range of sophisticated graphic capabilities that the Atari 400 and 800 have. There are no Star Raiders clones for the Apple or TRS-80 because those machines are simply unable to imitate the smooth player motion of the Atari. They are also unable to quickly mix text and graphics the way the Atari can.
One big difference between the Atari and the Apple or TRS-80 is the way information is put on the television screen; the Atari display list concept, although harder for a novice to use, is much more powerful and flexible than screen display methods used by other computers. The other important difference is Atari’s player-missile (PM) graphics, which other computers lack.
Other Atari features that give it expanded graphic capabilities are its inexpensive graphic input devices (joysticks and the new light pen), and the easy use of color intensities for shading three dimensional pictures. Together with the assembler/editor cartridge, these features allow the user to create exciting visual displays and informative graphics.
Much of this column is “technical” in the sense that it refers to parts of memory not mentioned in the Basic manual, or to concepts in computer graphics that are beyond the scope of Atari Basic. This does not mean that beginners will not benefit from reading it; beginners can become advanced programmers quite rapidly. Also, if you’re a novice programmer and have ever wondered how some of the nifty things that you see in the Atari games are done, read on— many will be explained shortly.
If one intends to do much machine language programming— especially graphics programming— on the Atari, knowing about the various hardware registers is essential. Unfortunately, the only manuals from Atari are poorly assembled, full of typographical mistakes, and expensive. Still, if the following discussion makes you want to delve further into the Atari, you should purchase the Operating System User’s Manual and Hardware User’s Manual. Together, they cost $30 (including shipping), and can be obtained from Atari, Attention: Barbara Burbridge, 1344 Bordeaux Dr., Sunnyvale, CA 94086. In this column, bytes that are associated with hardware or screen manipulation are called registers, and are addressed in hex. The bits of a byte are referenced from the rightmost (lowest order) bit. Thus, “bit four” refers to the fourth bit from the right.
Every microcomputer has a way of displaying objects and text on the screen of your television. The computer stores the information (“put these characters here,” “make this area green”) you have given it in memory, while memory-to-screen hardware reads the information and turns it’ into a signal for your television screen or monitor.
Apple and TRS-80 computers use bitmapped graphics. The memory which the hardware reads to display the screen (screen memory) consists of a list of data. In the Apple’s low-resolution mode, each pixel (dot on the screen) is described by four bits; a 0000 means that a black dot is to be displayed, 01 1 1 a blue dot, etc. Thus, the memory-to-screen hardware does not need to do much analysis on the screen memory in order to convert it to a television signal pixel by pixel.
The Atari, on the other hand, does not keep this sort of map. It uses a display list, which can be thought of as a program for the memory-to-screen hardware to run to produce the signal for the television. The display list program includes commands to produce blank or solid color horizontal lines, change the graphics mode, start getting information from another part of memory, and type text on the screen.
The display list is not as easy to use as bit-mapped graphics, but it allows you to make much more complex screen images. It gives you the opportunity to use many graphics modes at once, and makes changing the screen a very fast process. Learning to use it to its fullest is not hard.
The display processing hardware is fast enough, relative to your ability to move memory around so that animation is easier to program with a display list than with bit-mapped graphics. Although some animation can be done from Basic (see below), using the display list and machine language gives great flexibility to the advanced graphics programmer.
Basic programs cannot move objects on the screen very rapidly due to the speed of program execution. Even player-missile graphics. Atari’s super-fast system for displaying moving objects on the screen, seems slow when called from Basic. Clearly, assembly language programs run much faster than Basic programs, and there are some special techniques to make interactive graphic programs run smoothly. The technique used by Atari in their games to move objects gracefully on the screen is called display-list interrupt processing. (A special thank you to the programmers at the Bit Bucket in Newton. MA for much of the following discussion.)
Figure 1. Player 0 Player 1 Player 2 Player 3 12345678 12345678 12345678 12345678 1 XX 2 XX X X 3 XX XX XX 4 XX XX XXXXXXXX XX 5 XX XX XXXXXXXX XX 6 XX XX XX 7 XX XX XX 8 XX X X
Figure 2. PORTA ($D300) Joystick reading Bit 7 6 5 4 3 2 1 0 Right Left Back Fwd Right Left Back Fwd Jack 2 Jack 1
A brief explanation of interrupts: an interrupt is a flag which gets checked every time a certain process is about to be executed. If the flag is on, the process is not executed, and the program jumps to another area of the program (called the interrupt code). When the interrupt code has a return instruction saying that it is finished, the program then starts the process from which it was interrupted.
Some interrupts are checked each time the machine performs an instruction, while others are checked during pauses in machine operations. The display list can be interrupted at two levels: while the electron beam is returning from the bottom of the screen to the top, or while the beam is returning from the right of the screen and moving down one line. The first is called a vertical blank interrupt, the second a line interrupt.
The television screen is filled every sixtieth of a second: since the Atari uses 248 of the 262 screen lines, you have about 8.4% of one sixtieth of a second to perform operations on the screen. This is about 1400 microseconds, of which about 10% is taken by the CPU for memory refresh. You have enough time to perform around 500 assembly commands (1.8 cycles per microsecond, with an average of 4.5 cycles per command).
If the interrupt routine keeps the interrupt flag turned on, then the routine will execute, display the screen, and loop until the flag is turned off. This is sometimes useful if you can write most of the code necessary to run your program within the constraints of the interrupt routine. To return to your controlling program, all you have to do is turn the interrupt off. The controlling program runs while the screen is displayed and the interrupt routine is executing.
A typical graphics-oriented Basic game program would set up the game board, initialize the score counters, poke the interrupt code into memory and turn on the vertical blank interrupt. It would only return to the Basic program for score keeping, or to change the playing field if it were a multi-board game. The interrupt code would be responsible for reading the joysticks, moving the players, and determining whether an important event had happened.
The feature which allows the Atari to do the most advanced video displays is Player-Missile (PM) graphics. Much of what is known about the use of the PM subsystem has been explained in this column in previous issues. Two aspects of PM that have not been covered are collision detection and animation.
You will need some familiarity with the PM subsystem to understand fully the following section, although you can get most of what you need to know from this column in the January 1981 issue of Creative Computing. There is so much that can be done with PM that no article can pretend to cover it all, since combining PM and other Atari-specific features can yield wonderful new results.
Once you have the players and missiles moving around the screen, especially in a game situation, it is useful to know when a player hits another player, or hits a missile, or even when it (or a missile) moves to a part of the playfield that is a certain color.
To see if two PM objects have hit. Atari has provided the collision registers. Every sixtieth of a second, the Atari determines all current collisions, and turns the appropriate bits on in the collision registers described below. The collision registers are cleared by writing anything into the HITCLR register ($D10E), and have data only in the lowest four bits of each byte.
Registers M0PF, M1PF, M2PF and M3PF ($D000-$D003) describe the missile-to-playfield collisions, and P0PF. P1PF, P2PF and P3PF ($D004-$D007) describe the player-to-playfield collisions. The lowest order bit of $D004 being on means that player hit playfield (an object written in color 1, SETCOLOR register 0), the next higher bit means it hit playfield 1, and so on.
Registers M0PL, M1PL, M2PL and M3PL ($D008-$D00B) detect collisions between players and missiles: registers P0PL, P1PL, P2PL and P3PL ($D00C-$D00F) detect collisions between two players. Missile 2 hitting Player 3 would be shown by the third lowest bit of $D00A being set to 1. Similarly, Players and 1 hitting each other would be indicated by bit of $D00D and bit 1 OF $D00C being set.
The Atari’s PM subsystem can also be used for limited animation. This is done by setting up the four players as pictures, and having only one visible at a time. This is done by having players 1, 2, and 3 set to the background color for an instant, with player set to a different color, then 0, 2 and 3 being background with 1 a different color, and so on. If you change the horizontal position registers as you switch color, you can simulate movement. Figure 1 shows how to draw the four players to animate a board rolling end over end from left to right.
In its Assembler/Editor manual. Atari recommends that I/O be done through your Basic program, and that assembly language should be only used “when its speed advantages outweigh the difficulties of programming in assembly language.” This is overly cautious for advanced programmers, especially in terms of joystick input.
The main advantage of including your joystick-reading routines in the machine language subroutines that you are using in your Basic programs is increased accuracy of response. There are many Basic routines for reading the joystick and testing whether it is straight up, or determining the X and Y directions. An assembly language program to return the same information is much faster than any Basic subroutine, and can be done up to sixty times a second (the rate at which the port information is updated).
The ports on the front of the Atari are controlled and read by hardware registers. Jacks 1 and 2 are considered Port A, and jacks 3 and 4 are Port B. To read a joystick in jack 1, the port A control (called PACTL, $D302) must have the third bit set on. The status of the joystick is read in the four low order bits of byte PORTA, which is $D300 (see Figure 2). A bit set to zero means that the switch in a particular direction is pressed. The values for the directions correspond to those returned to Basic by the STICK(n) call.
Port B is controlled by PBCTL ($D303), with jacks 3 and 4 being read from PORTB ($D301), similar to port A. The joystick triggers for both ports are read in the lowest bit, or $D010 through $D013, with a zero indicating that the button is pressed.
Using joysticks for positional input is not hard, although there are other exciting ways to give the Atari the coordinates of a desired location on the screen. While joysticks are good for giving directions (“move me up and to the left”), you often only want to point to a specific position on the screen (“move me to here.”) Two new input devices are now available: the light pen and the graphics tablet.
A light pen does not give off light; it reads the light from your television screen. You touch the light pen to the screen to indicate a desired set of screen coordinates. The Atari light pen figures out where you are pointing by watching the electron beam of the television and calculating how long it was since the beam was at the top left of the screen. The pen is polled every sixtieth of a second.
The position of the light pen is read from hardware registers PENH ($D40C) and PENV ($D40D). The first byte is the horizontal position, ranging from 0 to 227; the second byte is the vertical position, ranging from 0 to 130. You can determine the screen coordinates of the point by figuring out the range of the screen compared to the range of values for PENH and PENV.
Another very useful input device is a graphics tablet. Many are now available for the Atari. A graphics tablet is a tabletop device, usually around 18″ × 18″, and flat. By touching the special pen to the surface of the tablet, you receive a pair of XY coordinates, as with the light pen.
The big advantage of the tablet over the light pen is that you can lay a piece of paper on the tablet and trace images or take data from it. Some applications include accurate drawing (no more messy joystick pictures), tracing pre-drawn pictures as input to programs, and getting responses from questionnaires quickly and accurately. Many of the tablets come with extensive software packages to make using them even easier.
If you own another home computer, or have shared programs with friends who do, you may have seen that the other machines do not have the ability to shade pictures. The Atari, with its intensity-selection capability, allows you to draw three dimensional objects with greater realism by using shading.
Using a computer to shade curved surfaces is complex, but it is certainly possible. For a very complete discussion of shading to achieve realism in computer drawings, you should read Principals of Interactive Computer Graphics by William Newman and Robert Sproull (McGraw-Hill). This book is an excellent reference for most topics in computer graphics, although it mostly deals with larger computers.
Other uses for the intensity control are in computer animation (for explosive colors, twinkling stars, etc.) and highlighting text without using inverse video characters. The Atari offers much in the way of precise choice of color for graphics applications.
Many graphics features you see in Atari games are simple extensions of the features listed above. For instance, to make game setup more interesting, you can set all the color registers to the background color, set up any necessary initial graphics, and reset the registers to their proper colors at the last instant (PM color registers can be used this way as well).
The limitation on the number of colors on the screen at any given time can be quite frustrating, but there are ways around it. The most simple is to use the PM subsystem to draw background, gameboards, or other features. A triple-width player and its associated missile can take up a fair amount of the screen if necessary. Using PM adds four new colors.
Also, the four missiles can be used to draw vertical lines on the screen. A little-known feature is that you can set the width of the missiles to single, double or triple width using register SIZEM ($D00C). The lowest two bits are for missile 0, the next two for missile 1 and so on. Set the bits to 00 for normal width, 01 for double width and 11 for triple width vertical lines.
Using line interrupts, you can change the color register for a particular player while it it being drawn. Thus, you can have multi-colored players. Or, using a single line interrupt halfway down the screen, you can change a single color register back and forth so that objects change colors as they move from the top of the screen to the bottom. It is unfortunate that line interrupts have virtually no documentation in Atari’s manuals.
There are many more graphics capabilities of the Atari computers than can be listed here, and many are undocumented. The Operating System User’s Manual and Hardware Manual, although sketchy in some areas, is helpful for many applications. Very little of the third-party software that is currently available has the extensive use of Atari-specific graphics that Atari’s games have; as better documentation becomes available, this may change.
CREATIVE COMPUTING VOL. 7, NO. 7 / JULY 1981 / PAGE 204
This month, with newlyweds David and Sandy Small handling the technical information in part two of their article on the Antic chip. I’d like to give an overall view of the special abilities of the Atari Computers.
After taking over as Editorial Director of Creative Computing in December. I spent three months commuting from New Hampshire before I could buy a house and move to New Jersey. During that period. I sought guest writers for Outpost Atari. May’s guest columnist was Dr. Mike Dunn, the editor of the Atari Computer Enthusiasts Newsletter. 3662 Maple Dr.. Eugene, OR 97405 ($8 a year). June’s guest columnist was Paul Hoffman, director of the Boston Atari Club. 48 Norfolk St.. Cambridge. MA 02139.
Very few programmers have learned to take advantage of the special features of the Atari. It will not be until programmers learn to combine several of these techniques into a single program that the Atari will really be appreciated. These special features are very important if you are programming the Atari, as programs that do not use them will have a hard time competing with those that do. We currently have articles planned on all of them.
The Atari is designed for use in the home by consumers, not just technical wizards. This shows in many ways. The RESET key is located away from the rest of the keys, and is protected by a plastic shield to prevent hitting it accidentally. Special function keys. START. SELECT. and OPTION, are provided separately from the rest of the keyboard for ease of use by the consumer.
All parts of the Atari are designed to stand up to the type of abuse that is to be expected in the home. Eor example, when Atari designed the joystick, they fully expected my 7 year old son to swing it by the cord and bang it into the floor, so they put strain reliefs on the cables and built it strong enough to take a lot of abuse.
Atari also realized that consumers don’t like keyboards: the paddles, joysticks, and light pen were designed into the system. One of the easiest ways to tell that an Atari programmer knows what he or she is doing is to find that the keyboard is completely disabled early in the program, with all input from the other devices. This is the reason the Atari 400 has such a limited keyboard. Programs written for consumers probably shouldn’t use the keyboard at all.
Atari knew that it would take a fast computer to provide the capabilities the consumer needed. One of the reasons the Atari is more expensive than many of their competitors is that Atari specified costly, high speed parts. Their microprocessor chip runs 80% faster than a standard 6502. This means every other part has to be of high enough quality to keep up. In addition, they added the Antic chip, a custom designed microprocessor to handle the most time consuming task, processing the video display.
The real competence of the Atari is in some special features designed into the machine for the use of advanced programmers. These features are very powerful, and for that reason they demand a lot of programming skill to use. However, they can give a lot of polish and professionalism to a program.
Every color graphics display in a computer with limited memory requires a compromise. You essentially need one bit of memory for every distinct dot you wish to draw on the screen, plus additional bits to specify the color of each dot. If you want very high resolution and many different colors, you must have a tremendous amount of memory just to tell the computer what to display. This leaves very little memory for your program. The Atari has several different display formats, from a double wide, double height text mode that requires very little memory, to high resolution graphics nuxles that take a lot of memory. This selection allows the programmer to use only the amount of memory needed for display purposes.
This powerful feature allows the programmer to efficiently establish and maneuver up to five players or four players and four missiles on the screen. These players and missiles tan use separate colors, be different widths and heights, and can even take priori!) over each other so that when two of them are at the same location on the screen, the one “in front” conceals the other. Players and missiles are independent of other parts of the display, so that you can have text or graphics on the screen and have your player pass right over them. Or, by changing the priority register, you can have the player pass “behind” other objects and displays.
With player missile graphics, there is a series of registers that tell whenever a player makes contact with another player, another missile, or an object drawn on the playfield. This makes it possible to cheek elaborate interactions between objects without having to write a routine that compares the location of each object with the location of each of the other objects.
There is no particular reason why the table of shapes stored in the computer has to be a set of upper and lower case letters, numbers, punctuation marks, and symbols. Why not have a set of 100 different spaceships? With the Atari, you can have both, plus a table of over 100 different interstellar objects and several other tables as well. You can switch from one character set to another instantaneously and print a space ship on the screen as simply as you print the letter “a”.
Due to the design of a television set, which calls for the picture to be drawn in a series of horizontal lines across the screen, it is much easier for a computer to provide smooth horizontal motion than smooth vertical motion. Some of the best video games, including Space Invaders, have been designed around this limitation, calling for most action and movement to take place in the horizontal plane, and allowing sudden jerky motion in the vertical plane. Atari has carefully built into their computers some tricks to enable programmers to have smooth vertical motion as well, though it takes a lot more work and skill than horizontal motion.
Really fancy tricks with video displays require the ability to synchronize precisely the microprocessor and the video display. It is very tricky, but this built in capability of the Atari allows you to do such things as change the color registers two thirds of the way down the screen, always at exactly the same point. This involves alternating between color schemes 120 times a second and timing each change to within a hundred-thousandth of a second.
It looks complicated in the Atari to set a given color register to a particular color, and then specify the color register instead of the color when you are programming. But this complex procedure provides a great ileal of power. It allows you to change instantaneously the color of an object just by changing the content of the register. and avoids redrawing the object. By switching colors between a foreground color and the background color, you can even make objects appear and disappear.
Sound, like color, is a major advantage in most programs. However, it can be difficult to use sound in a program if you have to use the microprocessor chip to produce the sound, for a single chip can only do one thing at a time. With four built-in voices in the Atari, the central processor needs only to specify the characteristics of one of the voices and turn it on. It then goes to other tasks until it is time to turn the sound off. No microprocessor time is required to maintain the sound.
The Atari is designed for easy expansion and change. The address lines in the computer are designed to handle 192K of memory, using three 64K memory cards in an Atari 800. The 64K cards would presumably be based on the next generation of 64K RAM chips, which are too expensive at the moment, but the computer is already designed to use them. This would require a different operating system ROM, but changing the ROM is as simple as adding a memory card is now. Already there are products like Ramcram from Axlon that offer 32K byte memory cards instead of 16K. Axlon also offers a 256K memory expansion interface. (Axlon. 170 Wolfe Rd.. Sunnyvale. CA 94086)
Atari’s ROM cartridges also make it easy to change languages. Unlike the TRS-80 or the PET, which require ROM to be dedicated to Basic even when you are not using it, it is normal in the Atari to unplug Basic and plug in the Assembler cartridge or something else.
It may be some time before we routinely see programs that combine non-keyboard input, extensive use of multiple colors. (I have seen 18 colors used effectively on the screen at one time, and 256 colors in a color pattern I player missile and character graphics, fine scrolling, and multiple character sets. One game which uses all of these techniques is currently under development at Atari, and 1 expect it to have an overwhelming impact on future computer games.
Atari has not been reluctant to share the techniques. For serious program developers, they have a support staff and offer seminars. This sen ice is only available for persons with demonstrated commercial potential, usually software houses advertising Atari software. For amateur (but skilled) programmers, they make available their operating system reference manual for $30. Use this address: Operating System Manual. 1346 Bordeaux Ave.. Sunnyvale. CA 94082. They are actively cooperating with magazines, user groups, and others trying to interpret the mystery of their machine to the general public. They are also working on future manuals and documentation, as well as software Uxils. to aid programmers. These software tools include several more programming languages, including an advanced Atari Basic, a Microsoft Basic. Forth, and Pascal.
At the National Computer Conference in Chicago on May 5th, Atari announced that the 8K Atari 400 was being discontinued and that the price on the 16K version was being reduced to $399. This move seems to be in response to the new Commodore VIC-20, announced at $299, but with only 5K of memory.
CREATIVE COMPUTING VOL. 7, NO. 8 / AUGUST 1981 / PAGE 200
Over the last two months we’ve discussed the Atari display list (DL) and its graphics-characters capabilities in separate articles in Creative. In this column we’ll look at some of the higher-powered features of the DL and provide a complete table of display list opcodes for future reference.
First, a note from a friend at Atari. In the last article, we found the display list via: START = PEEK(741) + 256*PEEK (742) + 1. This can be simplified by using: START=PEEK(560) + 256*PEEK(561). The 560-561 pointers to the display list point directly to the DL, not to the byte before it, as do the 741-742 pointers, and are more reliable under strange operating conditions. I’m told. I’ll use the 560-561 pointers from now on.
The display list, you’ll recall, is a program written for a special processor called Antic. Antic handles much of the display generation for the Atari and leaves the main 6502 processor available for other work. Last month we discussed the character and graphics opcodes for the Atari: this month I’ll present a complete list of all the opcodes, then devote the rest of the article to notes and explanation. I’ll try to keep the list short and concise, for reference purposes, and leave the explanations and examples for later. At first it will probably seem confusing, but read on.
There are three main groups of DL opcodes. There are also some modifiers which may be applied to the “base” opcodes, much as a sharp or flat may be applied to a base musical note. However, just as certain notes may not be modified with a sharp/flat, certain DL opcodes may not be modified in certain ways.
Blanking opcodes. When Antic encounters one of these, he generates a certain number of blank display lines (background). He doesn’t look to display memory or do anything else; he just takes a break and generates blank scan lines. From one to eight blank lines can be generated by these opcodes. The blank line, like any display block, extends all the way across the screen horizontally.
Modifiers: Only a display list interrupt may be added to these opcodes.
Character/Graphics opcodes. When Antic encounters one of these, he fetches bytes from display memory, determines the graphics mode, and puts something on screen. A complete list and discussion of these is available in “Atari Graphics Unveiled” in the June and July issues of Creative.
Modifiers: Horizontal scroll, vertical scroll, load memory scan and a display list interrupt may be added here.
Two special codes. JMP is a JUMP for Antic, it tells Antic to continue looking for instructions elsewhere. It is an equivalent to a GOTO in the display list. It is followed by a 16-bit address of where to continue.
JVB is a jump to the start of the display list, and wait for a new screen refresh to begin (automatically). It is followed by a 16-bit address, which by the way doesn’t have to be the start of the original display list; it can also be a completely new list. The important point is that JVB waits until the screen is refreshing again before allowing Antic to continue. Modifiers: Only a display list interrupt may be added here.
|Number of blank scan lines||Hex opcode||Decimal opcode|
|Basic Graphics Mode (if any)||Vertical Size||Horizontal Size||Colors||Graphics/Character||Hex||Decimal|
JMP 01 hex (01 D)
JVB 41 hex (65 D)
Table 1. Display List Opcodes.
To add a modifier to a given opcode, just add the number shown for that modifier to the base opcode, then use the number for the opcode.
Horizontal Scrolling. This capability added to an instruction means that section of the display may be smoothly scrolled in a horizontal direction. Add 10 hex (or 16 decimal).
Vertical Scrolling. This capability allows smooth vertical scrolling. Add 20 hex or 32 decimal).
Load Memory Scan. (A three-byte instruction is implied if you use this opcode.) This tells Antic where to find display memory, and resets Antic’s pointer to that location, no matter where he currently is. Add 40 hex (64 D) to use this.
Display List Interrupt. The execution of this instruction causes Antic to force the 6502 processor to interrupt (to the location specified in locations 200 and 201 H (512.513D). Requires writing to a location to allow interrupts.
1. Horizontal and vertical scrolling are neat additions to graphics capabilities. They are there to help make your job easier and provide some effects that you would otherwise have to work hard to generate.
Scrolling is making the display appear to “roll by”—an object on the display comes into view, is run across the screen, and disappears on the other side. (The Atari coin-op game where you fly over enemy terrain, bombing targets that roll underneath you, is an example of scrolling. This game could be implemented on the 400/800, if you’re looking for a saleable project, by the way.) Normally while editing you’ll see the Atari scroll data up off the top of the screen.
In order to have a display “scroll,” we must first output it to the TV in unmoved format, then move it, then output it again. This will cause the display to shift once. Repeatedly doing this causes a scrolling effect. All our displays, generated by Antic, are stored in memory and are put on the TV 60 times a second, so what we have to do is change display memory in such a way that it will cause a scroll.
If the display memory is changed so that all information in it is copied 40 bytes up, in graphics 0, then on the next refresh the former top line will be replaced by the information in the line below it (lines are 40 bytes long, remember). You’ve seen this effect when the Atari scrolls something up offscreen, as during a long set of PRINT’S. And, if we were to move the data in the display memory up just one byte, the screen would appear to move to the left, for the contents of the second byte would now be displayed in the TV position of the first byte, and so on down the screen. (See Diagram I.)
This is a good way to do scrolling if you are working in assembly language. The amount of data that must be moved, however. (960 bytes in graphics 0) is so large that it becomes impossible for Basic to do the job quickly enough. There is a way to do scrolling from Basic without moving a large block of memory. Instead of having Antic look at the same place in memory for display memory and moving things around in memory, let’s change where Antic looks and leave the memory alone. (Diagram 2.)
For example, if we were to tell Antic that screen memory started one byte down from where it really did. Antic would miss the first byte of memory, and the entire screen would seem to scroll to the left. Antic wouldn’t know the difference (or care), but to us, the screen will seem to have scrolled horizontally. If we were to tell Antic the screen memory starts 40 bytes down from where screen memory actually starts, he’ll miss the first line of data (assuming graphics 0), and the screen will scroll up. You can obtain some neat demonstration displays this way. Try Program 1 to scroll the screen horizontally. Program 2 to scroll it vertically, and Program 3 to do it both ways! These programs all just modify the pointer Antic uses to find display memory, and are a good deal of fun to leave running in a computer store.
However, all this gives us is coarse vertical/horizontal scrolling. When we rewrite display memory or such, we shift things eight dots or eight scan lines (in graphics 0). This gives us a very jerky display. So, Atari provided us with the capability to smooth out the scroll; you can shift the display vertically or horizontally the number of “fine” dots you need to make it smooth, then rewrite display memory or change Antic’s pointer to continue. You cannot scroll more than the distance between coarse scrolls; you can think of it as fine tuning only between channels if you like. It is limited to 0-7 (or 0-16 depending on mode) dots scrolled, which neatly fits our graphics scroll.
On the Atari, scrolling is only a positive value. In other words, you cannot scroll something “down” using the scrolling register; you must start with it fully scrolled up and scroll it “less upwards” to achieve a downward effect. How much you wish a display scrolled up is written into a mapped memory location.
Thus, in order to make a smoothly scrolling vertical display, we need to select our “coarse” vertical position with the display memory and such, then select how many “fine” scan lines to go up from that position. Presumably we would increment the number of lines to go up, to move the whole display up. When we reach seven increments, our capability to fine scroll is finished, and we have to rewrite display memory (and set our vertical scroll to 0) to get that eighth scan line up. Then we would start over with incrementing our vertical scroll location. A downwards scroll is nearly the same thing; just have it start at +7 scroll, then work down to 0, shift memory, and so on.
The display list entry for a given display block must be modified to allow scrolling. If you write something to the scroll register, but don’t change the display list, nothing will happen.
Here are some details on how fine scrolling is implemented:
Antic normally displays a fixed number of scan lines per display mode. Well, when we scroll vertically, Antic doesn’t do this anymore. When Antic encounters the beginning of a “scrolled zone—”a group of display list opcodes with vertical scroll modifiers— he treats the beginning and end of the scrolled zone differently than he normally would. Display blocks in the middle of a scrolled zone are handled normally. When he first finds a scroll-marked display block, he doesn’t display the normal number of scan lines for that display block. He only displays the bottom slices of the display block, the exact number determined by what is in the scroll register. Because the top line of the scrolled zone then becomes shorter than it normally is, the lines below it seem to move up. (Diagram 3.)
The lines in the middle are displayed normally, then when Antic reaches the end of the scrolled zone, he only displays the top few lines of the last scrolled display block. Again, how many he displays is determined by the scroll register. This is necessary to make the total number of scan lines in the scrolled zone remain constant. Why? If the total changes, the display below the scrolled area will move, depending on the scrolled area. By having the top and bottom display blocks short, but the total of them adding up to one display block size always, we get a fixed size scroll zone. Also note that we will have “lost” one display block in the scrolled area: remember, only pieces of two display blocks, whose total is one display block, are shown. One stays missing.
This is a strange but effective way of doing things. If you run Program 4, you will see vertical scrolling in action. This program writes two separate vertical scrolled zones into the display list, then scrolls them. Note that the display shrinks two scan lines when you run the program; this is the missing top of the top line and bottom of the bottom line (adding up to one display block height) in two places; hence there are two less displayed lines. Also note how the scrolling letters seem to disappear behind the fixed letters. They aren’t really disappearing, they are just not being displayed completely.
This capability requires some experimentation which may make clearer what I’ve been saying: Atari uses some tricky hardware to make their machines work as they do. Horizontal scrolling, by the way, should give you some entertainment as it involves modifying the amount of data per line in the display memory.
The vertical scroll register is at D405 hex (57239 D), and the horizontal scroll register is at 1)404 hex (57238 D).
2. Load Memory Scan (LMS)
This instruction is very useful and quite necessary to know about if you’re doing much graphics work. It is a helpful tool for advanced graphics but using it is necessary in other applications due to the way the Atari hardware is designed.
When Antic first learns where display memory is, it takes that 16-bit value and puts it into a register inside itself. When it wants data from memory, such as a line of characters. Antic looks to this register to find out where it currently is in display memory. It then fetches the byte at that location, and increments (he register so it points to the next byte. Trouble is the internal register is only 12 bits. (The other four bits are latches, if you’re interested.) This means that as Antic goes along, if it hits a 4K boundary in memory (goes past a 1000 hex address point), it will run out of “fingers to count on” and start all over again!
This has caused extreme frustration at Atari. I’m told, and is one of the most difficult-to-debug and commonplace problems encountered in Atari programs. So remember, don’t let your display memory cross a 4K boundary without resetting that pointer via a load memory scan. Place the 16-bit value of where to continue in display memory in the two following bytes. By the way, you’ve seen this instruction before; it’s the 66 near the beginning of the display list. The 66 is a two (or graphics 0, one line) instruction, with a 64 modifier added to it. (If you counted the display list example in the previous article, there’s only 23 GR.O instructions, and one 66 instruction to make up 24.) The 4K boundary means 4K in absolute memory address, not relative to the DL.
This instruction also accounts for some of the graphics 8 display list instructions. Graphics 8 uses 7680 bytes of display memory, well past the 4096 byte Antic limit, and it thus needs this instruction to reset the pointer. If you dump the GR. 8 display list, you’ll see what I mean.
I should also mention before it drives someone to insanity that the display list itself cannot cross a IK boundary because of the same sort of thing. Antic’s pointer to where it is in display list is 16 bits long, but the top six bits are latches only; they cannot count. You must use the JMP instruction to pass a IK boundary in the display list (1048 decimal). If you start getting screwy display list results, you may have passed a IK boundary with the DL or a 4K boundary with the DM without using JMP/LMS to reset the pointers.
3. Display list interrupts.
Setting this bit (those of you with binary counting experience may now realize that the modifiers are just top bits set in the opcode) causes the 6502 processor to be interrupted, and sent to the location specified in 200 and 201 hex. This is a really handy capability; you can have the 6502 busily doing something else, and when the display reaches a certain point, you can have the 6502 interrupt what it’s doing for a special update. One example that comes to mind is changing a color register halfway down the screen to get more than four colors displayed at once. Using this capability requires some assembly language work, and I will provide an example of it in a later article. In the meantime, those of you who know assembly can POKE into 200 and 201, and use an RTI to get back once done processing.
After the display list instruction is executed, you’ll interrupt to your service routine. By the way, you’ll also need to write a C0 hex (192D) into location D40E (or 54286D) to enable this type of interrupt. Because of the usefulness of DLIs. I will include two general purpose assembly routines in a later article devoted to assembly aids for Basic (primarily in player-missile and DLI related items); one shifts all color registers to user-determined values wherever the user places an interrupt, the other is a kind of color display list, where every display block has five colors for the color registers and displays its data in those specified colors.
Well, there you have it, a complete list of DL opcodes. You can do a tremendous amount with this powerful tool. Look at what’s been done on the Apple, a machine without the power of the display list, for example. Apple users have the equivalent of the Atari without the display list or other graphics tools and only a few graphics modes, and someone managed to implement Galaxian on it!
Coming up next month, now that we’ve covered the display list quite thoroughly, is Player-Missile graphics. This is the second graphics generation system on the Atari and will give you more power than ever. The display list alone is extremely powerful, especially with capabilities to synchronize the 6502 and interrupt on a given display block; Player-Missile should give you the final powerful tool to do about any animations you wish on your custom display (list) background.
Good luck and happy hunting with your Atari! (Our thanks to ComputerLand in Austin. Texas for allowing me to use their equipment to check these programs.)
CREATIVE COMPUTING VOL. 7, NO. 10 / OCTOBER 1981 / PAGE 230
Back when I was first working on an Atari 800, I tried to figure out Player-Missile graphics. First, I asked everyone I knew what P-M was and how it worked. “Well, like, man, it’s a special subsystem with a reserved memory area that’s really hard to use and you use Peek(106) to find an open page, man, then bump it 1024 and do a DMA write then hit D-Mack-Tull and Grack-Tull and it fires up.”
And perhaps the best of all. “It’s how they did Star Raiders.” (Mind you, these were people who programmed Ataris for a living!)
Said I. “There’s got to be a better way.” I then retired to a hilltop in Tibet with an Atari, and several hundred pages of manuals lent to me by some kind soul in a San Jose computer club, and started trying to figure it out. Long did I puzzle over the hardware manual (and still do). My back issues of Creative arrived with snow on them, all wrinkled up. But at last I won out: I returned understanding Player-Missile graphics. And in this column I shall try to impart to you, willing disciple, some of this knowledge, and help you achieve good karma.
In order to understand P-M graphics, it’s best to start at the low level hardware functions and work up to the automatic DMA. So let’s start at the TV.
A TV picture is made up of horizontal scan lines output from a source in time with the scanning of the TV. In our case, the source is the Atari, busily outputting data to the TV and trying to keep up with it. A special chip, called Antic, was designed to aid the main 6502 processor of the Atari in generating displays. (A longer and more detailed view of how the Atari generates these graphics appeared in the July 1981 issue of Creative, but is too long to repeat here.)
There’s another chip called CTIA. CTIA is the chip which handles the assignment of color and such: Antic is more concerned with getting data from memory location for CTIA (by DMA) in time to keep up with the TV. Because they are reincarnated slave drivers and prone to such behavior, the Atari designers felt that CTIA just didn’t have enough to do, so they thought up another task for it.
CTIA already keeps track of where he is horizontally on each scan like they reasoned. So let’s have him keep an eye on a memory location at the same time for a special purpose. In this location is a number that corresponds to a horizontal position on the TV screen. I’ll refer to the memory location where horizontal information is stored as a “horizontal position register.”
Now, let’s say CTIA should find that his horizontal position at the moment happens to equal this horizontal position register. Great things begin to happen! CTIA looks to another register to get one byte of data (this one I’ll call a “graphics data register”). He then takes the first bit of data in this register, puts it onscreen as a dot if 1, or skips it if 0. For the next dot over, when he gets there, he does the same thing. He works his way from left to right onscreen, left to right through the eight bits of data — most significant bit first. He puts these eight bits of data onscreen at a color and luminance specified by yet a third special register, the “color/lum register.”
Listing 1. 1 REM PROGRAM 1 5 REM **** DEFINES 10 HPOS0=53248 20 BITS0=53261 30 COL0=704 40 SIZE0=53256 100 REM **** PROGRAM 1 110 REM **** GENERATE A FIXED PLAYER 120 REM 130 REM **** SET HORIZ POSITION 140 POKE HPOS0,120 150 REM **** SET COLOR 160 POKE COL0,202:REM B.GRN,INTEN=10 170 REM **** SET DATA 180 POKE BITS0,218:REM 1011 0101 190 REM **** SET SIZE 200 POKE SIZE0,0
Listing 2. 1 REM PROGRAM 2 5 REM **** DEFINES 10 HPOS0=53248 20 BITS0=53261 30 COL0=704 40 SIZE0=53256 100 REM **** PROGRAM 4 110 REM **** SHIFT PLAYER COLORS 120 REM 130 REM **** SET HORIZ POSITION 140 POKE HPOS0,150 170 REM **** SET DATA 180 POKE BITS0,203:REM 1100 1011 190 REM **** SET SIZE 200 POKE SIZE0,0 300 REM **** SHIFT PLAYER COLOR 310 FOR PCOL=0 TO 255 STEP 2 320 POKE COL0,PCOL 330 NEXT PCOL 340 GOTO 310
Listing 3. 1 REM PROGRAM 3 5 REM **** DEFINES 10 HPOS0=53248 20 BITS0=53261 30 COL0=704 40 SIZE0=53256 100 REM **** PROGRAM 2 110 REM **** ROTATE A PLAYER 120 REM 130 POKE HPOS0,150:REM HORIZ POS 150 REM **** SET COLOR 160 POKE COL0,202:REM B GRN,INTEN=10 190 REM **** SET SIZE 200 POKE SIZE0,0 300 REM **** MODIFY BIT PATTERN 310 FOR T=0 TO 255 320 POKE BITS0,T 325 FOR DELAY=1 TO 100:NEXT DELAY 330 NEXT T 340 GOTO 310
Listing 4. 1 REM PROGRAM 4 5 REM **** DEFINES 10 HPOS0=53248 20 BITS0=53261 30 COL0=704 40 SIZE0=53256 100 REM **** PROGRAM 2 110 REM **** ROTATE A PLAYER 120 REM 150 REM **** SET COLOR 160 POKE COL0,202:REM B GRN, INTEN=10 170 REM **** SET DATA 180 POKE BITS0,203:REM 1100 1011 190 REM **** SET SIZE 200 POKE SIZE0,0 300 REM **** ROTATE RIGHT 310 FOR T=40 TO 200 320 POKE HPOS0,T 330 NEXT T 340 GOTO 310
Listing 5. 1 REM PROGRAM 5 5 REM **** DEFINES 10 HPOS0=53248 20 BITS0=53261 30 COL0=704 40 SIZE0=53256 100 REM **** PROGRAM 5 110 REM **** MODIFY PLAYER SIZE 120 REM 130 REM **** SET HORIZ POSITION 140 POKE HPOS0,120 150 REM **** SET COLOR 160 POKE COL0,202:REM B GRN,INTEN=10 170 REM **** SET DATA 180 POKE BITS0,203:REM 1100 1011 300 REM **** SHIFT PLAYER SIZE 310 POKE SIZE0,0 315 PRINT "SIZE NORMAL" 320 GOSUB 1000 330 POKE SIZE0,1 335 PRINT "SIZE X 2" 340 GOSUB 1000 350 POKE SIZE0,3 355 PRINT "SIZE X 4" 360 GOSUB 1000 370 GOTO 310 1000 FOR Z=1 TO 1000:NEXT Z:RETURN
To get an overview of this process, let’s say we have 150 stored in the horizontal position register, a color of bright green at 10 intensity in the color/lum register, and a bit pattern of 11001011 stored in the graphics data register. When CTIA, busily scanning across the screen, finds his current position is 150, he will plot— dot dot (skip) (skip) dot (skip) dot dot— from his current position, working to the right (continuing the sweep). The dots will be green. CTIA will then finish the rest of the scan line with display list stuff. In the next line, he will again get to the 150 midway across the screen, and copy the graphics data register at the same color onto the TV. This process will happen every time he hits 150 horizontally. (Figure 1.)
What we end up with is a vertical green stripe at horizontal position 150, exactly matching the bit pattern above. Let’s go ahead and run a program to do just this, so you can see what it looks like. (See Listing 1.)
Now, I’d like to have you briefly play around with this program to learn about the registers. Let’s change the color/lum. the graphics data, and the horizontal position registers. The effects will be. respectively, changing the color, the bit pattern, and the horizontal position of the stripes. Run the programs in Listings 2, 3, and 4 to see these effects.
Next, I’ll have to introduce you to the “size register.” The size register tells CTIA how big to make his dots when he puts them on screen. He can make them normal size, twice as large, or four times as large. (All he does is plot the same data two or four times as he scans across the screen if we tell him to. Thus the stripe will grow from the left, with the left border [at 150] staying constant.) Run the program in Listing 5 to see this particular effect. A zero in this register means times one, a one means times two, and a three means times four.
The object you see in front of you, this stripe, is known as a “player.” If you imagine an object that is exactly the same as a player, but is only two bits wide instead of eight, you have a “missile.” Hence the name, “player-missile.” Well, you say, is that all? What good is a green stripe in the middle of the TV that doesn’t even shut off when I quit running my program?
That’s a good point. The thing is, we don’t have to leave the data in the graphics register on all the time. Let’s say we leave it all 0’s for a while from the top of the screen. CTIA will plot nothing, just putting the usual background stuff (display list) on that scan line at 150. But if we should suddenly put some data— for example, 11111111 —in the graphics data register, it will plot in the next scan lines from then on. Then we can turn it off, by putting 0’s back into the register, and we will have a square onscreen. It will really be a stripe, with a lit square in the middle of it, but to us it will appear to be just a square. (Figure 2.)
Now this is starting to get useful. We could change the shape of the square by changing the data we put in the graphics control register. We can move it horizontally by changing the horizontal position register, or vertically by changing where we decide to click the graphics data register on and off. Then we will have an object moving around on the TV screen. Did 1 say “an” object? I should mention there are four players and four missiles available, each with separate controls. Table 1 lists the control memory locations.
Missiles have the same colors as their players. Missiles can also be grouped together to form a fifth player; four missiles two bits wide equal one player eight bits wide, get it? All missiles have the same size and same data (usually two on bits anyway).
Some of the above demo programs should now become clear. I have set Player 0’s horizontal position to 150, his color/lum to bright green at intensity ten (color/lum register = 16 *(color number) + Lum), and his graphics data to CB hex, or 203 decimal. Alas, I haven’t written the color/lum information to the location listed above, however. Let me pass on a sad experience to tell you why.
Inside the operating system of the Atari, invisible to you, exists what are known as “shadow registers.” These registers contain what the O.S. currently thinks the color/lum and so forth of the players and missile are. Now at the beginning of every screen refresh, the hardware registers for P-M for which the O.S. has a shadow are reloaded from the O.S. data. This means if you go in and change the addresses shown above, with a POKE, in some cases the change will only last until the next refresh: 1/60th of a second. So for the O.S. shadowed hardware locations listed above. POKE into the O.S. shadow register, not the hardware register, for a permanent effect.
Another good use for this table is direct Setcolor poking. Now all a Setcolor does is take the color, multiply it by 16, add the lum you specify, and POKE it into the above O.S. shadow locations. For a much faster Setcolor, just do a POKE (play field O.S. shadow location), (16*color) + Lum. The O.S. locations to look for are the play field areas, also known as color registers to the Basic programmer. (2C4-2C8 H)
Listing 6. 10 REM PROGRAM 6. USE ALL PLAYERS. 20 REM DEMONSTRATES PRIORITY 30 POKE 623,2:REM P0 HIGHEST 40 REM POKE A 2 TO HAVE PLAYERS 2,3 50 REM HAVE LOWER PRIORITY THAN PLAYF 60 POKE 704,4:REM COLOR P0 GREY-LO 70 POKE 705,58:REM COLOR P1 ORANGE-HI 80 POKE 706,90:REM COLOR P2 PURPLE-HI 90 POKE 707,196:REM COLOR P3 GREEN-LO 100 REM 110 POKE 53261,255:REM BITS P0 120 POKE 53262,255:REM BITS P1 130 POKE 53263,255:REM BITS P2 140 POKE 53264,255:REM BITS P3 150 PRINT "PLAYER 0 = GREY" 160 PRINT "PLAYER 1 = ORANGE" 170 PRINT "PLAYER 2 = PURPLE" 180 PRINT "PLAYER 3 = GREEN " 190 REM CYCLE THROUGH PRIORITIES 200 FOR X=1 TO 15 210 POKE 623,X 220 PRINT "PRIORITY CODE =";X 230 FOR T=36 TO 218 STEP 3 240 POKE 53248,20+T:REM PLAYER 0 250 POKE 53249,T:REM PLAYER 1 260 POKE 53250,218-T:REM PLAYER 2 270 POKE 53251,239-T:REM PLAYER 3 280 FOR Z=1 TO 15:NEXT Z 290 NEXT T 300 NEXT X 310 GOTO 200
Table 1. Player-Missile Controls.
|Missile 0||D004-(53252)||D011-(53265)||same as P0||D00C-(53260)|
|Missile 1||D005-(53253)||same||same as P1||same|
|Missile 2||D006-(53254)||same||same as P2||same|
|Missile 3||D007-(53255)||same||same as P3||same|
O.S. Shadow Registers**
- ANTIC -
- CTIA -
|22F H (559D) D400 H (DMA CTL)***||26F H (623D) D01B (PRIOR)|
|2F3 H (755D) D401 H (CHA CTL)||2C0 H (704D) D012 (Player 0 Color)|
|230 H (560D) D402 H (Dlist L)||2C1 H (705D) D013 (Player 1 Color)|
|231 H (561D) D403 H (Dlist H)||2C2 H (706D) D014 (Player 2 Color)|
|2F4 H (756D) D409 H (CH BASE)||2C3 H (707D) D015 (Player 3 Color)|
|2C4 H (708D) D016 (PlayField 0 Color)|
|2C5 H (709D) D017 (PlayField 1 Color)|
|2C6 H (710D) D018 (PlayField 2 Color)|
|2C7 H (711D) D019 (PlayField 3 Color)|
|2C8 H (712D) D01A (PlayField 4 Backgnd Color)|
Refer also to Atari columns listing hardware register addresses.
* O.S. or Operating System -A control progam that allows the computer to react with other programs, and handle input and output.
** Shadow Register- An area in memory that stores information to be transferred to a hardware control device.
*** DMA or Direct Memory Access- Allowing information in memory to be transferred from one location or device to another without using the main microprocessor. The Atari uses the Antic microprocessor to transfer information from memory to the television screen.
Abbreviations CTL = Control DList = Display List H = High Byte L = Low Byte
The information provided so far will be quite helpful. You can get some really neat color effects running players back and forth. Try the program in Listing 6 for this effect and feel free to modify it in all sorts of ways. Note the effect, though, when two players run over one another, or when a player runs over some background (display list) data!
When two players or missiles (or more) “collide,” what happens? CTIA will have two “on” bits of data from two objects and has to resolve the priority conflict. First, it lets you know they have collided (remember, that doesn’t just mean their horizontal position has matched, it means that while plotting “on” bits of graphics data registers CTIA encountered two in the same place) writing into a “collision register.” CTIA then follows a priority scheme to tell it which player to plot over which, and whether to plot players over display list data. You select the scheme you want with a POKE. Table 2 lists the different schemes.
So far we have a vertical stripe onscreen and some interesting color effects. Basic is nowhere near fast enough to switch the thing off and on to get an “object” on screen. And even if we were to work in assembly language, we would tie up the 6502 processor doing all this on/off stuff and writing the graphics registers, and it wouldn’t have time to do much else.
The designers of the Atari followed this identical train of thought. Let’s listen in and see how they solved it.
Table 2. Priority table.
Location D01B (53275) contains the priority data. Use OS 632D as this address is shadowed.
Select either 8, 4, 2, or 1 to POKE with. Adding them gives odd results consisting of black overlapping regions. (Experiment!)
|P-F0||P-F0||Play 0||Play 0||Highest Priority|
|P-F1||P-F1||Play 1||Play 1|
|Play 0||P-F 2||Play 1||Play 1|
|Play 1||P-F3&5||P-F 1||Play 3|
|Play 2||Play 0||P-F 2||P-F 0|
|Play 3||Play 1||P-F 3&5||P-F 1|
|P-F 2||Play 2||Play 2||P-F 2|
|P-F 3&5||Play 3||Play 3||P-F3&5|
Add 10H (16D) to let all missiles become the color of playfield 3. Thus you can position all the misssiles for a fifth player object. Add 20H (32D) to have a different color (a logical OR) occur during an overlap.
“Play” refers to a Player. “P-F” refers to a playfield, or display list generated, object. (Remember the four available color registers?)
Use this priority chart aftr you have decided who should have priority over whom, to select the scheme that you wish.
Designer 1: “Well, the problem is, we don’t want to tie up the 6502 with all this player-missile stuff.”
Designer 2: “Yeah, kinda reminds me, though of another situation. Remember when we did the display list, and we didn’t want to tie up the 6502 with doing the screen refreshes?”
Designer 1: “Right We let Antic do all the display work to free up the 6502...Hmmmmm.”
(Antic, hearing this, realizes something is about to happen and quietly slinks toward the door, tail between legs and ears drooping, trying to attract as little attention as possible.)
Designer 1 and 2 have the same idea at the same instant: “Let Antic do it! We’ve already assigned him to do display work; why not let him help us with P-M? Antic! Here boy! Now where did he go?”
Needless to say, they caught old Antic and set him to helping with P-M graphics. You don’t have to use Antic to help you, as we’ve seen with our demonstration program. Antic is just there to help if you want him to, to take some of the load off the 6502 (and you). There are applications which benefit from both using Antic and not using him, so keep the above “direct” player-missile graphics method in mind. It’s what Antic uses anyway.
Let’s set up a table in memory. It will be 256 bytes long. Each byte in that table corresponds directly to one horizontal scan line on the TV. (Well, yes, there are 192 scan lines on the TV, so there’s a bit of overkill. You’ll note a player extends all the way offscreen, past where Antic is generating display list scan lines.)
Now if we tell him to, CTIA will tap Antic on the shoulder each time one of his horizontal position registers matches his current position, and say, “Hey, give me the graphics data byte for this particular line number.” Antic will go to memory, fetch the byte, and feed it to CTIA. The neat thing is, once you set up the 256 byte area and tell them to get going, the 6502 is free to do whatever you want it to. The “Player-Missile DMA” becomes completely automatic then. (Figure 3.)
In this method, an object is defined by a few 1 bits in this table which correspond directly to a vertical stripe onscreen. If we turn on a few bits, they show up in the corresponding screen position. If we copy them upwards in the byte table, the object they show will move up. We control their horizontal position via the horizontal position register, color through the O.S. shadow register, size, and so on.
This technique is what most articles on P-M graphics use. As we’ve seen, it is a higher-level technique than the more direct method of writing to the hardware registers; it just involves letting Antic do our work for us. Be sure to keep the earlier technique in mind, though.
There are many things you have to do to initialize P-M DMA and get things rolling. You have to reserve a location in memory for player-missile DMA. Finally, you must set colors and such (as shown here) to get the players to show up.
It is difficult to learn to apply P-M graphics using the DMA table, with all the pesky details, any other way than by example. There are just too many registers and options in a list to be anything but a reference aid. So what I’ll do is take a P-M example from an earlier issue and go through it, in detail, with you, pointing out the miscellany on the way. There really isn’t much new, now that we’ve covered the hardware addresses and concepts.
In January George Blank gave a fine example of DMA P-M graphics. (See Listing 7.) Let’s go through the program briefly to see how it works in relation to our example.
Line 30 POKEs into an O.S. location which instructs the system to work with a normal size playfield; i.e.. 40 characters across. This location is really an O.S. shadow, however, for a hardware register called DMACTL (Direct Memory Access Control). There are two electrical switches between Antic, CTIA, memory, and the world, which tell them whether to do automatic DMA or let you do all the work. DMACTL is one. GRACTL (Graphics Control) is the other. Both switches must be on for P-M DMA to occur. This POKE turns on DMA by poking DMACTL, so now all Antic is waiting for is the GRACTL switch to be switched on.
Listing 7. 10 DIM A$(10),B$(100) 20 GRAPHICS 8 30 POKE 559,62 10 POKE 53248,120 50 POKE 704,88 60 I=PEEK(106)-8 70 POKE 54279,I 80 POKE 53277,3 90 POKE 53256,3 100 J=I*256+1024 110 FOR Y=J+120 TO J+137 120 READ Z 130 POKE Y,Z 140 NEXT Y 150 FOR X=48 TO 221:GOSUB 500:NEXT X 160 GOTO 150 320 POKE Y,Z 500 POKE 53248,X 510 RETURN 600 DATA 60,60,60,60,60,60 610 DATA 255,255,255,255,255,255 620 DATA 60,60,60,60,60,60
And now, for another brief detour. DMACTL also controls whether Antic can go to memory at all, as in whether he can generate display list graphics. A POKE (DMACTL).O will turn your screen completely off, because Antic can no longer fetch bytes from memory.
Now why would we ever want to do this? For one thing, it is a good way to flash something on screen. Another is that if we change display lists, we want Antic turned completely off so that he can’t run wild between them in the time it takes to POKE both bytes of a new DL start address.
Line 40 is a POKE to Player 0’s horizontal position register, putting the player at 120. Line 50 POKEs Player 0’s O.S. shadow register to a pink color. (No surprises so far, right?) Now, you’ll recall we need 256 bytes for our table. I hate to tell you this, but if we’re going to run one player this way, we have to run them all this way, which means four players and one missile times 256 bytes. There’s some wasted space, so the total comes out to 2048 bytes for our bitmaps of the player missile stripes. We’ll fetch the 2048 bytes at the end of available user memory. To do this, we find where the Atari thinks the end of memory is, which it figures out upon startup, and then back up 2048 bytes from there. We do this by looking at location 106, which tells the number of 100 hex, or 256-byte, “pages” of memory it has available. Since 2048 is 8 × 256 bytes, we use that value to tell the Atari where the beginning of our Player-Missile data tables will be. We POKE that location into 54279, which is “PMBASE,” the base address of the Player-Missile data.
Table 3. P-M Table Area. PMBASE * 256 = start of this area BASE ADDRESS + 0 wasted space. + 767 + 768 - Missile Data. Missile data is packed side by side, 4 missiles of 2 bits per byte. M3 : M2 : M1 : M0 + 1023 + 1024 Player bitmap. Top byte is top line of TV (above viewing area). + 1279 + 1280 + 1535 Player 1 bitmap. + 1536 + 1791 Player 2 bitmap. + 1792 + 2047 Player 3 bitmap.
Next, we must POKE into a switch known as GRACTL. GRACTL and DMACTL, remember, are the switches that keep P-M graphics off. We already turned DMACTL on at the start of the program. We POKE a 3 into 53277, which translates to, “Turn Player-Missile graphics on and enable Antic to start getting bytes from memory.” You’ve seen 53256 before; this is player 0’s size register. A 3 POKEd in there means size times four.
Well, our player-missile graphics are now running. Whatever junk is in memory at this point is being busily pulled out of memory by Antic, fed to CTIA, and displayed on the TV. We had best put some sort of bit pattern in the table, so let’s do that now. Line 280 sets J equal to I (which you will recall was the start of the P-M table) * 256 (because that value was in 256 byte pages). Thus, J points to the beginning of the P-M table in real memory. We add 1024 to it, because that’s how far in this table the Player data is. with the data for the other players and missiles around it. (See Table 3.)
Hence, J now equals the beginning of the Player data. The FOR loop in the program runs from J + 120 to J + 137, which is from the 120th to the 137th byte in the middle of the player, or right about midway down the screen. We read in data and POKE it into the middle of the player bit map. This data is in the form of a “cross,” where the 60’s are: 00111100, and the 255’s are 11111111. This data will be output in the form of dots for 1 bits and blanks for 0 bits, so at this point we have a cross onscreen, still in pink. Next, we have a loop which POKEs the horizontal position register from 48 to 221, and over again. This will move our player stripe, with all but the cross on it invisible, across the screen. (Figure 4.)
There shouldn’t be much mystery left in players and missiles now. Antic is just poking our hardware graphics register for us, with a table of data we feed him, so the 6502 isn’t kept busy. We still move him horizontally as always, set his color, and select his size the same way. To move him vertically, we have to re-POKE the data in the byte table, and here a clever program in the April “Outpost: Atari,” page 195* may help you: The data in a string are specified as the data in the player field, so by manipulating the string, you manipulate the player (at high speed). This is very valuable when you try copying a list from Basic and see just how slow it really is.
There are many options open to us. some of which you may never use, but some of which may be just the ticket for displays you’re thinking of. I’ll try to go over one of these options, now that we have a bare-bones P-M example going and the basics down, in a later article. You may also want the information on the Atari hardware registers which has appeared recently; it will give you the exact patterns needed to POKE into such areas as DMACTL or a size register.
Now that you have the essential information about player missile graphics, you may wish to experiment with moving players around on the screen. Listing 8 will display the horizontal memory pointers. Listing 9 will demonstrate vertical scrolling. Listing 10 combines horizontal movement with vertical scrolling, and Listing 11 demonstrates vertical scrolling combined with altering the display list in a text mode. Have fun, and be sure to experiment!
*(Note: there is an error in line 580, which should read 580 POKE VTAB+7,1.)
Listings for Programs 1-4 were inadvertently omitted from the August “Outpost: Atari.” They are listed below.
Program 1. 10 REM PROGRAM 1. HORIZONTAL 20 START=PEEK(560)+256*PEEK(561) 30 REM ANTIC DISPLAY MEMORY POINTER 40 REM IS AT START+4 AND START+5 50 REM 100 X=PEEK(START+4)+256*PEEK(START+5) 110 PRINT "START OF DISP MEMORY=";X 200 FOR Y=X TO X+80 205 PRINT "POINTER=";Y 210 REM SPLIT Y UP INTO TWO BYTES 220 YHI=INT(Y/256) 230 YLO=Y-(YHI*256) 240 POKE START+4,YLO:POKE START+5,YHI 250 FOR DELAY=1 TO 20:NEXT DELAY 260 REM 270 NEXT Y Program 2. 10 REM PROGRAM 2. VERTICAL L 20 START=PEEK(560)+256*PEEK(561) 30 REM ANTIC DISPLAY MEMORY POINTER 50 REM IS AT START+4 AND START+5 50 REM 100 X=PEEK(START+4)+256*PEEK(START+5) 110 PRINT "START OF DISP MEMORY=";X 130 REM 140 REM SCROLL UP 200 FOR Y=X TO X+(40*20) STEP 40 210 GOSUB 1000 260 REM 270 NEXT Y 500 REM SCROLL DOWN 510 FOR Y=X+(40*20) TO X STEP -40 520 GOSUB 1000 530 NEXT Y 540 GOTO 140 550 REM 990 REM CALCULATE HI, LOW BYTES 1000 YHI=INT(Y/256) 1010 YLO=Y-(YHI*256) 1030 POKE START+4,YLO:POKE START+5,YHI 1040 RETURN Program 3 10 REM PROGRAM 3. VERTICAL AND HORIZ 20 START=PEEK(560)+256*PEEK(561) 30 REM ANTIC DISPLAY MEMORY POINTER 40 REM IS AT START+4 AND START+5 50 REM 100 X=PEEK(START+4)+256*PEEK(START+5) 110 PRINT "START OF DISP MEMORY=";X 130 REM 140 REM SCROLL UP 200 FOR Y=X TO X+(40*20) STEP 40 210 GOSUB 1000 260 REM 270 NEXT Y 500 REM SCROLL DOWN 510 FOR Y=X+(40*20) TO X STEP -40 520 GOSUB 1000 530 NEXT Y 550 REM 600 REM SCROLL LEFT 610 FOR Y=X TO X+40 620 GOSUB 1000 630 NEXT Y 650 REM SCROLL. RIGHT 650 FOR Y=X+40 TO X STEP -1 660 GOSUB 1000 670 NEXT Y 680 GOTO 140 990 REM CALCULATE HI, LOW BYTES 1000 YHI=INT(Y/256) 1010 YLO=Y-(YHI*256) 1030 POKE START+4,YLO:POKE START+5,YHI 1040 RETURN Program 4. 1 REM PROGRAM 5. VERTICAL SCROLL DEMO 5 VSCROLL=54277 10 START=PEEK(560)+256*PEEK(561) 20 REM *** PUT SOME DATA ONSCREEN. 30 GRAPHICS 0 35 FOR T=1 TO 24 36 PRINT "THIS IS LINE #";T 37 NEXT T 40 REM *** ALTER DISPLAY LIST TO V 45 REM *** IN TWO AREAS. 2 + 32 = 34 60 FOR Y=START+10 TO START+13 70 POKE Y,34 80 NEXT Y 81 FOR Y=START+17 TO START+20 82 POKE Y,34 83 NEXT Y 85 REM *** SCROLL UP 90 FOR Y=0 TO 7 100 POKE VSCROLL,Y 105 GOSUB 200 110 NEXT Y 115 REM *** SCROLL DOWN 120 FOR Y=7 TO 0 STEP -1 130 POKE VSCROLL,Y 135 GOSUB 200 140 NEXT Y 150 GOTO 90 160 REM *** SHORT DELAY LOOP 200 FOR T=1 TO 50:NEXT T 210 RETURN
CREATIVE COMPUTING VOL. 7, NO. 11 / NOVEMBER 1981 / PAGE 258
Recently I received a letter from a new Atari user. In it, the writer said “Help! My friends with Apples are making fun of DM and my ‘Aturkey 800.’ as they call it. They say it can’t display more than five colors onscreen at once and their Apples can. They call me up at 4:00 a.m. to tease me. Can you help?”
Well. I couldn’t ignore such a plea. So here it is, the first of a two-part column on making your Atari generate many different shades of color on the same TV frame. Along the way. I’m going to cover very briefly topics that have been covered in previous columns (i.e., what is a display lisC.’i. Expect them to be just briefly defined, for there isn’t room to cover them again. Rather. I’ll concentrate on new topics, in a ground-up approach to color generation on the Atari. Hopefully I’ll leave you with a wider knowledge of how the machine generates color, with a few example programs to show you just how much it can do.
The Atari is, in my opinion, far and away the finest graphics machine available for the price. It was designed by the wizards of Atari to be able to create as many TV displays as you can imagine. The designers knew that many new applications would be thought of long after the hardware was designed, and thus made everything as open ended as possible with a great deal of flexibility. (I suspect a stripped-down Atari 800 resides inside many Atari coin-op games.)
“Wait a minute.” you say. “what’s this about ‘flexible’ and ‘open ended?’ The Basic book says, five colors maximum. That’s not very flexible.”
Let’s discuss how the Atari handles color a bit, understand why there’s a five color limit, and then get around it using tome of the flexibility designed into this machine. One demonstration program will show 128 shades of color on the same screen! This demo has been seen by few people indeed. Along the way. I’ll even provide a nifty demonstration program called “Sunset.”
Why Five Colors?
When the designers of the Atari worked out the details of its color handling, they decided on a technique which would give the user as much flexibility as possible, rather than locking him into just one method.
Inside the Atari is stored a copy of what’s currently going on the TV screen, this is called “display memory.” For a given point, or a group of points onscreen, some way of determining the color to be used when plotting must be stored in this memory. In the Atari the color information is stored in a “color register.” When in display memory the color of a point is specified, a color register number is stored rather than the actual color code.
In other words, to plot a red point, one tells the display memory that this point will be plotted in the color and brightness stored in (say) color register 1, then one puts color red at some brightness into that color register. See Diagram 1.
10 REM PROGRAM #1. COUNTS THROUGH 20 REM ALL POSSIBLE COLORS. 25 POKE 709,14:REM SHADOW REGISTER 30 FOR C=0 TO 255 STEP 2 40 POKE 710,C:REM SHADOW REGISTER 50 PRINT "COLOR REGISTER=" ;C 60 FOR DELAY=1 TO 190:NEXT DELAY 70 NEXT C Program 1.
There are five available color registers, numbered through 4. Color register 4 is also known as the “background color register.” It specifies the color and intensity for any place onscreen where nothing else is written. (In the Graphics modes 3-7, this means the color of the area between any plotted pixels: in mode 0, it means the area around the character display field, not the area “behind” characters. It’s the border area.)
This approach may seem more complex than necessary, but it has its advantages. First, it saves memory: only two bits at most are required to specify the color of a pixel in the display memory. Second, it adds flexibility. All we have to do to change the color of every point onscreen using the same color register is modify that register— one POKE. To turn the entire screen red, then black. (“RED ALERT!”), we need only two POKEs. In a machine without the Atari’s sophistication, massive and slow rewrites of display memory would be required. See what I mean about leaving the Atari open ended for applications that would be thought of after the machine was designed?
Color registers are one byte long. The upper four bits determine the color (0-15), the lower four specify the brightness. Now only the top three of the four brightness bits are used: hence, there are eight levels of brightness, and 16 colors, or 128 possible total shades of color. Note that in this register, values 0-15 are color in different intensities. 16-31 are color 1, and so on; if we just count this register upwards, we’ll pass through all 16 colors, each increasing in intensity to the highest level before moving on to the next. If you’ll run Program 1, you’ll see the screen counted through all the different shades. Table 1 lists the different colors.
Value Color 0 Grey 1 Gold or Light Orange 2 Orange 3 Red-Orange 4 Pink 5 Purple-Blue 6 Blue 7 Blue 8 Blue 9 Light Blue 10 Turquoise 11 Green-Blue 12 Green 13 Yellow-Green 14 Orange-Green 15 Light Orange
Table 1. Color Register Values (as stored in upper 4 bits of color register).
How Basic Handles Colors
Up in high memory there’s some memory which isn’t read-write, regular old RAM. Rather, when one writes or reads from these locations, one is communicating with other chips in the Atari which help support the 6502 (more on this later). (Diagram 2.) Anyway, one chip, called CTIA, handles colors and graphics generation. There are five locations (“hardware color register addresses”), which are the five color registers. Now CTIA looks to these registers to find out the color needed for a given character/point, whenever it plots a new point. During the refresh process of updating the screen, it looks to the registers many, many times, fetching the colors for displayed data.
The operating system maintains five “shadow registers.” These are normal RAM memory locations. At the beginning of each screen refresh, these five color shadow registers are copied into the corresponding five hardware locations. Basic deals with these shadow registers. (A list of these also appeared in a previous article.) Why?
One reason for maintaining these shadows is that the CTIA color register locations are “write only”; one cannot read out those locations the color has just written in. Remember, they are not memory locations; they are other chips to which we write by POKEing simulated memory locations. Hence, if we wanted to read a color register and we didn’t have it stored somewhere (like a shadow register), we couldn’t. Being able to read registers is handy, for example, rotating a color from one register to the next; you use the O.S. shadow registers for this.
Basic’s SETCOLOR (color reg number), (col number), (lum number) takes: (16 × color number) + lum and POKES that value into the O.S. shadow register. One sixtieth of a second later, at the beginning of a screen refresh, the O.S. copies this value into the CTIA hardware color registers and begins to use it for plotting data onscreen. Incidentally, a direct POKE to the O.S. shadow locations is equivalent to a setcolor. For example. SETCOLOR 2, 4, 10 is the same as: POKE 710, (4*16) + 10.
The designers of Basic also had to come up with some means for the user to specify what color a given point or character should be. For this they have the COLOR (#) statement. It specifies which color register to use when plotting data, and remains in effect until the next COLOR statement.
The argument, unfortunately, is not a color register number. The designers of Basic tried to keep the user away from bits and bytes discussions; hence the COLOR argument at first appears random. Upon closer inspection. I determined what it actually was and the reasons for its arguments.
The argument of the COLOR statement is the data that are written into display memory to specify colors. The Atari has two- and four-color graphics modes, which uses one or two bits to specify color register. For example. COLOR is generally background because of a 00 written into display memory plots nothing, thereby forcing the background color to appear there. Next month we will leam how to get around it.
Hardware Registers (CTIA) O.S. Locations (Shadows) D016 (53270) 2C4 (708) PF0 D017 (53271) 2C5 (709) PF1 D018 (53272) 2C6 (710) PF2 D019 (53273) 2C7 (711) PF3 D01A (53274) 2C8 (712) PF4(BACK) Table 2. Color Registers. Graphics Mode 1.2 4.6: One Bit 3, 5, 7: Two Bit Color Register Character Modes - Unused 1 - Character lum only 2 - Char backgnd color/lum 3 - Unused 4 - Border col/lum - 3: Character 4 - backgnd/border Graphics Modes 0: Point color/lum 1.2.3: Unused 4: Backgnd 0: Point color/lum 1 : Point color/lum COLOR! x) Not used in graphics sense. Table 1 COLOR # Values. Not used in graphics sense. Notes: COLOR 1 SETCOLOR (n), color, lum always sets color register n. Hence, the color register number given is equvalent to the COLOR SETCOLOR register number. In chapter modes (0.1.2) more than 1 or 2 bits are written COLOR 1 into display memory. Hence the COLOR argument is actually COLOR 2 the character byte written in memory.
CREATIVE COMPUTING VOL. 7, NO. 12 / DECEMBER 1981 / PAGE 300
Last month we discussed the way Atari Basic handles color, and why normal Basic programs are limited to five colors. This month we describe a method you can use in your own Basic programs to allow up to 128 colors on the screen at one time.
A refresh of the TV screen occurs 60 times per second. The electron beam starts at the upper left hand corner, goes all the way right for one scan line, then does the next line down left to right, and so on. CTIA is responsible for feeding data to the TV in synchronization with this scan. For every dot plotted onscreen. CTIA looks again to its hardware color registers to find the color.
While a screen refresh is a darn fast thing to us, it isn’t particularly fast compared to the speed of the 6502 processor. We must not think of a screen refresh as an instantaneous event; rather, we must think in terms of how long the 6502 sees it taking, which is roughly an Ice Age or so.
If we could change a color register that CTIA was using halfway through a screen refresh, the screen below that point would reflect CTIA using the new colors. For example, if we were in Graphics 7 and motlified the background hardware register halfway through a refresh from green to blue, the screen will shift from green to blue in the middle of the TV frame for all those background points. (Diagram 1.)
If we were to put Basic to work changing the color register as fast as it could:
FOR R = to 255: POKE 53274,R: NEXT R
we’d find that Basic wouldn’t be able to get more than one change in per frame. This is because it’s so slow in execution.
and this is why only five colors can be shown at one time if we use just Basic. By the way, that total doesn’t include players and missiles.
What’s needed here is high speed help to assist Basic in getting a demanding job done. We have to use machine language.
Machine language, the human equivalent of which is called assembly language, is an art few programmers really go in for. The Atari will execute machine language instructions in times measured in millionths of a second. Alas, machine code is hard to understand, a pain to debug, and generally has other annoying characteristics, which is why “high level” languages such as Basic were developed in the first place.
On an Atari it’s a practically obscure art, practiced by a few magicians with strange materials (cartridges) and arcane knowledge (Quick, what’s a zero flag branch?). You can always tell an Atari assembly user, like me today, at our local Computerland, dressed in my long black robes and peaked hat. After several hours of intense meditation before the machine. I fell to work with such concentration that I forgot food and wife, leading to a fight and cold dinner later.
Now look. You have better things to do than annoy your sweetheart or spend hours in worship. And you don’t have to learn all about assembly language and pay cleaning bills for those black robes. You’d do better to use the genial and friendly Basic. Let someone else deal with the powerful and quite unforgiving assembly work, and use what they accomplish out of Basic.
So here’s the deal I propose. I’ll provide an assembly routine that’s easy to load and use from Basic. The routine will handle the demands of the 6502 so you don’t have to worry about them. By setting up various tables, again from Basic, in a fairly easy way, you can then have as many colors onscreen as you like, all without worrying about assembly, execution speeds, timing, and so on. This is the grey area between assembly and Basic, where the power of assembly helps Basic in a particularly tight spot. There will be more articles on this subject in the future: one, for example, will provide a high speed way to move players or missiles vertically (which you’ll recall involves copying a lot of data back and forth in memory, something Basic doesn’t do very quickly).
Now on to a discussion of display list interrupts, which is how we’re going to pull this off.
The Atari machines really have two processors in them. One is called Antic, and one is the regular 6502. Antic has its own special language and is devoted to display work. Antic works with “display blocks”; a “display block” is a group of horizontal scan lines, all in the same display mode. (Think of it as a long thin horizontal bar, eight scan lines high in Graphics 0, 16 in Graphics 2, and one in Graphics 8. Its height is determined by the size of plotted data in the particular mode.) Atari displays are composed of stacked display blocks. There are 24 stacked blocks in Graphics 7.
Previous articles have dealt with modifying the program Antic uses, called a “display list.” to achieve mixed graphics modes and other goodies, such as scrolling. There’s one change to the display list we have not yet covered because of its complexity and the requirement of using assembly language: the display list interrupt.
A display list interrupt is flagged by setting the top bit of a display list instruction. (To us Basic programmers, this means add 128 to the instruction.) For example, a Graphics instruction with a DLI added is 2+ 128, or 1.10. About any DL instruction can have an interrupt added.
Now what’s an interrupt? Well, imagine both Antic and the 6502, toiling away in the fields. Antic finds the top bit of its instruction set (128 added). It goes ahead and completes the current instruction or display block up until the last scan line, it turns and taps the 6502 on the shoulder (doubtless enjoying the moment, after the 6502 has given it so much work over the years) and says, “Drop immediately whatever you’re doing, and process (his request.”
The 6502 looks to locations 512 and 513 in memory. In this it finds 16 bits of address (stored in low, high format, for you advanced coders). The 6502 then jumps to that address. (Incidentally, a POKE to an Antic location is required to enable this sort of interrupt before the 6502 will be bothered.)
At the location whose address we put in 512 and 513 we must have an assembly language routine waiting to “service the interrupt.” or make the 6502 do whatever it is we went to all this trouble to make it do! At the end of this routine, we send the 6502 back to whatever it was doing originally with an RTI (return from interrupt! instruction. (Diagram 2.)
This is probably a new concept to Basic programmers. The best Basic analogy is the TRAP statement. TRAP specifies a line number to GOTO if there is an error, just as 512 and 513 specify where to go if there is an interrupt. Presumably at that line number you have written a routine to handle errors; this is the equivalent of the interrupt service routine. Finally, just as you never know, executing your Basic code, where an error might happen, you also never know when an interrupt will occur.
Here is the first of several overviews of what we are going to do. I’ll provide you with an “interrupt service routine” that will handle the above needs, written in assembly. It will reference a table controlled from Basic, and will work on any Atari, at any memory size, and allow you all sorts of different colors onscreen. It will be based on display list interrupts.
The development of an assembly routine that will be as flexible and easy to use as possible and still run on any memory size Atari is quite a task, (hence my hours of worship, etc.) However. I think what I’ve come up with will serve most users nicely.
First, the assembly routines must be able to fit anywhere in memory, since who knows what memory size your Atari has or how big a Basic program you’re using? Hence. I’ve placed the entire routine into a string (PRS), and I’ll let the Atari worry about where to put it.
If you’re lost, think of this. A string to us is a collection of characters, generally English words. Inside the machine all those characters are is bytes— one per character. An assembly routine is also just a collection of bytes. The Atari stores a string as a group of bytes, one at a time, in memory: hence, we could make the characters in the string (bytes) be the same as our assembly routine, and thus store the program in the string. (Diagram 3.)
The Basic routine I will provide is called by a GOSUB. It reads the bytes of the assembly program into the string, one at a time. (The CHRS function takes the contents of the argument and directly stores it in the string, which is just what we want since we don’t care about the actual characters.) After it sets the string up, it then ties the table of colors we’ll generate (just a second. I’m getting to that) to the program, enables display list interrupts, and returns.
The method I’ve come up with for specifying colors is to build a table for them, five at a time (for five color registers). Now each time there’s a display list interrupt, starting at the top of the table, the next five colors are copied into the hardware registers by servicing the program (in PRS). The idea is that the first display list interrupt causes the first five bytes of the table to be copied into the hardware registers, causing the colors of CTIA to change at that point. The next display list interrupt causes the second group of five color bytes to be copied into the hardware register, again changing the colors, going on down the screen. Hence, by setting interrupts, through modifying the display list from Basic, you can change colors any time you like from one display block to the next. This lets you get as many colors on the screen as you like, oriented towards display blocks. It can be thought of as a color display list. (Diagram 4.)
Next, how shall we set up the table? Let’s just use another string. COLS. The first five bytes (characters) of the string will thus correspond to the first display list interrupt colors, the next five bytes to the next five, and so on. Since my routine can address a maximum of 255 bytes this means we have a total of 255/5 = 51 interrupts, which is plenty, believe me. (If not, go buy a robe.)
The next problem is how the assembly routine figures out when we are at the top of the screen, in order to know when to begin at the top of the table (string) again. This is done by setting an interrupt at the very first DL instruction onscreen, which is a 112 (eight blank scan lines). There is a hardware register called VCOUNT which tells us which scan line we are on, from the top of the screen; we read it, and if it corresponds to the blanking line at screen top, we know to start at the beginning of the table again. The routine requires this interrupt to be set. If it isn’t, random colors will be generated as the 6502 sails past the end of COLS, cheerfully gobbling up loose data and using it to determine color/lum.
The Basic subroutine is called after you set up COLS, which is the table of colors. (It requires the location of COLS be tied down in memory before it tells the assembly program where the color table is.) Then it returns to you. See Program Listing 2. (Program 1 was in last month’s column).
Everything is now ready. Place your interrupts where you need a color register change, make sure you have the colors ready in the table (COLS), and the assembly routine will do the rest. The moment the display list is modified, the process of copying into hardware registers begins and the colors will change onscreen.
Since this is a confusing process involving many new ideas, let’s take a step back and get an overview of the entire process as we’ve covered it so far. This will. I hope, clear up any confusing points about how to use the routine.
Basic keeps “O.S. shadow registers” of the colors in the five hardware registers. When do we do a SETCOLOR, we change these O.S. registers. At the start of each TV refresh. 60 times a second, these shadow registers are copied by the operating system into the hardware registers. Now here the colors would stay, unchanged, for CTIA to look at, except for the special assembly routine we have.
The routine requires the “blank eight lines” instruction executed at the top of the frame to have an interrupt. Antic does that display block, generating blank lines, and at the end of it interrupts the 6502. The 6502 trots over to COLS, pulls out five bytes from the beginning of the tables (since this is the top of the screen), and copies them into the hardware registers. At that point the colors being generated by CTIA change to the new values just copied in.
Now again here things will stay until the next refresh unless we place another display list interrupt somewhere, and have five more colors ready in COLS. If we do. at the the end of that block the color register will again change, and so on. At the end of the refresh the O.S. register will once again (futilely) be copied into the hardware registers, just to be overridden by our routine again, and again.
We must determine where we want a color change, what color register must change (for remember the color registers are used differently between graphics modes), and plug in the right values to make a multi-colored screen.
Program 2. 10000 REM ************************ 10010 REM 10020 REM * DLI DRIVER / DAVE SMALL 10030 REM * YOU MUST DIM AND FILL 10040 REM * CDL$ PRIOR TO GOSUB HERE 10050 REM 10060 DIM PR$(50) 10080 REM 10090 REM * READ PROGRAM INTO PR$ 10100 REM 10110 READ X 10120 IF X=255 THEN 10300 10130 PR$(LEN(PR$)+1)=CHR$(X) 10140 GOTO 10110 10150 REM 10160 REM * PROGRAM AS BYTES 10170 REM 10180 DATA 72,138,72,152,72 10190 DATA 162,0,173,11,212,201,07,240,3 10200 DATA 174,01,02 10210 DATA 160,0 10220 DATA 189,03,04 10230 DATA 153,22,208 10240 DATA 232,200,192,5,208,244 10250 DATA 142,05,06 10260 DATA 104,168,104,170,104,64 10270 DATA 00,01,02,03,04,05 10280 DATA 255 10290 REM 10300 REM * LINK COL$ TO PR$ 10310 REM 10320 P=ADR(PR$) 10330 PHI=INT(P/256) 10340 PLO=(P-PHI*256) 10350 REM 10360 C=ADR(COL$) 10370 CHI=INT(C/256) 10380 CLO=(C-CHI*256) 10390 REM 10400 REM * POKE IN COL$ ADDRESS 10410 REM 10420 PR$(21,21)=CHR$(CLO):REM LOWCOL 10430 PR$(22,22)=CHR$(CHI):REM HI COL 10440 REM 10450 REM * POKE IN PROGRAM LOAD ADDR 10460 REM 10470 PXHI=INT((P+41)/256) 10480 PXLO=(P+41)-(PXHI*256) 10490 PR$(16,16)=CHR$(PXLO):REM XLO 10500 PR$(17,17)=CHR$(PXHI):REM XHI 10510 PR$(33,33)=CHR$(PXLO):REM XLO 10520 PR$(34,34)=CHR*(PXHI):REM XHI 10530 REM 10540 REM * POKE IN INTERRUPT ADDRESS 10550 REM 10560 POKE 512,PLO 10570 POKE 513,PHI 10580 REM 10590 REM * ENABLE INTERRUPTS (ANTIC) 10600 REM 10610 POKE 54286,128+64 10620 REM 10630 REM * ALL SET! RETURN. 10640 REM 10650 RETURN 10660 REM *********************
Program 2A. Assembler Routine for Display List Interrupts from Program 2. PHA 48H 72D TXA 8AH 138D PHA 48H 72D TYA 98H 152D PHA 48H 72D LDX #0 A2H 162D 00H 0D LDA $D40B ADH 173D 0BH 11D 04H 212D CMP #7 C9H 281D 07H 7D BEQ SKIP F8H 240D 03H 3D LDX $0102 AEH 174D 01H 1D 02N 2D SKIP LDY #0 A8H 168D 00H 0D LOOP LDA $0304,X BDH 189D 03H 3D 04H 4D STA $D016, Y 99H 153D 16H 22D D0H 208D INX E8H 232D IHY C8H 200D CPY #5 C0H 192D 05H 5D BNE LOOP 08H 288D F4H 244D STX $0506 8EH 142D 05H 5D 06H 6D PLA 68H 104D TAY A8H 168D RLA 68H 184D TAX AAH 170D PLA 68H 184D RTI 40H 64D (SCR1) 00H 0D (SCR2) 01H 1D (SCR3) 02H 2D (SCR4) 03H 3D (SCR5) 04H 4D (SCR6) 05H 5D (END) FFH 255D
Program 3. 100 REM * PROGRAM 3. 110 REM * SETS TMO COLORS FOR GR.O 120 REM 130 DIM COL$(50) 140 REM 150 REM * COLOR GROUP 1. 155 REM * CHARS=GREEN,BORDER=RED 160 REM 170 COL$(1)=CHR$(0):REM UNUSED 180 COL$(2)=CHR$(10):REM LUM 190 COL$(3)=CHR$((12*16)+6):REM COLOR 200 COL$(4)=CHR$(0):REM UNUSED 210 COL$(5)=CHR$((2*16)+6):REM BORD 220 REM 230 REM * COLOR GROUP 2. 235 REM * CHARS=ORANGE,BORDER=BLUE 240 REM 250 COL$(6)=CHR$(0):REM UNUSED 260 COL$(7)=CHR$(10):REM LUM 270 COL$(8)=CHR$((3*16)+6):REM COLOR 280 COL$(9)=CHR$(0):REM UNUSED 290 COL$(10)=CHR$((7*16)+6):REM BORD 300 REM 310 REM NOW CALL DLI DRIVER 320 REM 330 GOSUB 10000 340 REM 350 REM NOW POKE IN INTERRUPT AT 360 REM TOP;GET DISPLAY LIST START 365 REM 370 START=PEEK(560)+256*PEEK(561) 380 POKE START,112+128 390 REM 400 REM NOW POKE IN INTERRUPT HALWAY 410 REM DOWN LIST (START+6+15) 420 POKE START+6+15,2+128 430 REM 440 REM ROUTINE IS NOW RUNNING. 450 REM 500 STOP
Now for an example. This one will be in Graphics 0, the character mode. It’ll plot the top section of the screen in one color, the bottom in another.
Graphics 0 uses the same locations and no one told Antic to quit interrupting. However, as soon as the strings are shifted or destroyed, as during editing, the machine won’t have an interrupt service routine anymore, and it will quietly die. (Use RESET to avoid this.) The graceful way to exit the multicolor mode, by the way. is to remove the interrupts from the display list.
For the next demonstration let’s escalate things and put 16 colors onscreen at once, in Graphics 0. We’ll make each of the first 16 Graphics display blocks a different color.
We will thus need 16 interrupts; the one at the top of the screen (112), the one at the first true Graphics instruction, which is 66 (66=64+2; the 64 added to the 2, like the 128, is a modifier for display memory loading), and 14 more in the Graphics (2) instructions.
COLS will be length 16*5, or 80, since we have 16 interrupts.
Instead of 80 COL$=CHR$’s we will use instead a short loop. Remember a change of 16 is five color registers as listed in Table 1 (this is copied from the inside back cover of the Basic manual).
We’ll need two groups of five colors stored in COLS. The first will cover the colors from the first display list interrupt, at the top of the screen, to the second interrupt midway down the screen. The second will cover from midscreen to the bottom. COLS is set up with the colors in Table 2.
Our colors are now set up. We call the routine with GOSUB 10000. It returns to us shortly thereafter. We must now set our interrupts in the display list.
A Graphics 0 display list is shown in Table 3, to help us visualize what we will be modifying.
Hence, we POKE a 112+128 into START+0, to set our first interrupt (the instant that POKE is executed, the Atari’s colors will change to the values in the first five bytes, and another interrupt midway down the Graphics instructions (at START+6+15: POKE a 2+128). At that point, the colors will change again. What you’ll have onscreen are the specified colors, changing at the interrupt points to the new colors in COLS.
You’re in for a surprise when you push BREAK to halt the program. The screen stays changed! This is because the program and color strings are still in the change of color. (Program 4.) This loads COLS with our desired 15 color changes, with only the background color changing between each one, at the same lum. We then call the assembly subroutine, and set our interrupts with another loop:
POKE START,112+128 (blank lines interrupt) POKE START+3,2+64+128 (lms.gr.0 interrupt) FOR D=START+6 to START+6+13 (14 total) POKE D,2+128 NEXT D
Boom, there you have it. 16 different colors onscreen at once. You’ll want to play with this routine and try different luminances for characters, background, border.
One variation on this is to rotate the string once you have the interrupt routine working off it. The effect onscreen is rotating colors, with the shades of color slowly shifting up. This can be done by rotating COLS five bytes at a time. Add the following lines to Program 4:
500 COL1$=COL$(76,80) (get last five characters) 510 COL1$(6)=COL$(1,75) (append first 75) 520 COL$=COL1$ (and shift it into COLS)
Naturally, if you were mixing graphics modes, as more and more good software is beginning to do, you could just add an interrupt and more colors to shift displayed colors between modes. This can be quite helpful in drawing attention to a certain display. Hashing the display can be accomplished by just rewriting one byte in COLS to 0, then back; this will change a color register onscreen immediately.
That’s the beauty of the routine: all you have to do to modify the colors onscreen is modify the string. (I must give credit where credit is due for the original concept of using strings to manipulate memory to Creative’s own George Blank. A few columns back he made a player’s memory map area be a string, and manipulated the player up and down using string operators. This was a good idea, and this color routine is an offshoot of it.)
Well, on to a demonstration few have seen: 128 shades of color— all on the same screen. The first time 1 saw this, the person who programmed it dedicated the 6502 processor to updating color registers; it did nothing else. As such it wasn’t really useful, but it was a start. Here’s my version, which runs along with Basic.
100 REM * PROGRAM 4. 110 REM * 16 COLORS AT THE SAME TIME. 120 DIM COL$(255) 130 REM * INITIALIZE COL$ IN GROUPS 140 N=4 150 FOR C=1 TO 80 STEP 5 160 COL$(C)=CHR$(0):REM UNUSED 170 COL$(C+1)=CHR$(0):REM LUM 180 COL$(C+2)=CHR$(N):REM COLOR 190 COL$(C+3)=CHR$(0) 200 COL$(C+4)=CHR$(2):REM GREY BORDER 205 N=N+16 210 NEXT C 220 REM 230 REM * NOW CALL DLI HANDLER 240 REM 250 GOSUB 10000 260 REM 270 REM * NOW DO DL WORK 280 START=PEEK(560)+256*PEEK(561) 290 POKE START,112+128 295 POKE START+3,2+64+128 300 REM 310 REM * NOW POKE IN 14 MORE (GR/0) 320 REM 330 FOR D=START+6 TO START+6+11 340 POKE D,2+128 350 NEXT D 360 REM 370 REM PROGRAM IS NOW RUNNING. 380 REM 500 STOP Program 4.
Since we can only have 51 interrupts, we can’t do it the easiest way, where we shift into Graphics 8 and use 128 interrupts (there are 192 scan lines in Graphics 8). Instead, we will use multiple color registers on the screen side-by-side and shift them four at a time in Graphics 7.
Graphics 7 uses four of the five color registers: 0, 1, 2, and 4 (background). We generate the four blocks, each using one color register, by a simple nested loop and draw. (See Program 5 and Diagram 5.)
Graphics 7 has 96 display blocks, so let’s set a display list interrupt every third block, for 32 total, plus the one at the top of the page for 33. We’ll load each color register with a shade of color different from its neighbors just by counting up the 128 possible shades, and offsetting.
Now have a look at Program 5 listing. COLS initialization. Remember, a change of 2 is required to change one shade of color. We then poke in the DLIs as usual, this time using 13+ 128 (which is Graphics 7) for 32 of them and the usual one at the top. 112+128.
There you have it. 128 shades of color. all at once. But. I’m not done yet. Let’s rotate them.
All we need to do to rotate these colors upwards is shift them up five. The value in color register 4 will be shifted into register 3, and as such become invisible until it is shifted into 2, but no matter. A better routine could bypass the “hole” in the colors.
Program 5. 100 REM PROGRAM 5. 128 SHADES OF COL. 110 DIM COL$(255) 120 REM * DRAW FIGURE 125 GRAPHICS 7+16 126 FOR R=0 TO 1 127 SETCOLOR R,0,R*2 128 NEXT R 129 COLOR 1 130 CL=1 140 FOR X=1 TO 120 STEP 40 150 COLOR CL 160 CL=CL+1 170 FOR Y=1 TO 95 180 PLOT X,Y 190 DRAWTO X+40,Y 200 NEXT Y 210 NEXT X 230 REM * LOAD COLORS 240 CL=0 250 FOR T=1 TO 33*5 STEP 5 260 COL$(T)=CHR$(CL):REM COL REG 0 270 COL$(T+1)=CHR$(CL+64):REM COLREG 1 280 COL$(T+2)=CHR$(CL+128):REM COLREG 2 290 COL$(T+3)=CHR$(CL+192):REM UNUSED 300 COL$(T+4)=CHR$(CL+192):REM COLREG 4 310 CL=CL+2 320 NEXT T 330 REM * CALL DRIVER 310 GOSUB 10000 350 REM * SET INTERRUPTS 360 START=PEEK(560)+256*PEEK(561) 370 POKE START,112+128 380 FOR D=START+7 TO START+7+96 STEP 3 390 POKE D,13+128:REM GR.7 400 NEXT D 410 GOTO 110
Add these lines to Program 5 to rotate
This is Program 5 with rotate.
Note that I do string manipulations using a scratch string and only copy it into COLS when I’m done fiddling with it. This helps prevent the Atari from moving it somewhere with no warning due to changing length, as well as preventing weird screen flickerings, if COLS should temporarily be too short to provide enough data.
By now, if you’re running these programs, you’re seeing your Atari do things it has never done before. Let me now present to you the Sunset program which is based on a program which appeared previously in this column. It had three spirals, one-inside the other. Colors were shifted between them (each spiral was in a different color register, and they were in Graphics 7).
Well, the sneaky idea behind this routine is to use the shifting introduced in the previous program on the spiral routine. The initializations are a bit tricky: each color register is started up a bit offset from the others, so that each will have a considerably different color than the others, and the background is left completely off until halfway down the screen. Then the colors are shifted with the top half of the string being shifted up and the bottom half being shifted down, an effect very much like a sunset over water. I’ve added a few random stars in the background on the upper half to twinkle as the color registers change. (Program 6.)
Some notes: The Atari variable table can get full of holes, if you do lots of editing, and the Atari has strange cleanup of unused strings. If you start getting unexpected problems, try LISTing the program out to storage then ENTERing it back in: this will clean up the variable table. I’ve had little problem with this, however.
If you come across a particularly nifty effect, you might mail me a copy at the address appearing at the bottom of the column: I’ll try it out and maybe include it in a future column if it’s really good.
Be sure to experiment, have fun, and go create something! □
Program 6. 100 REM ** PROGRAM 6, SUNSET. 110 REM *** 120 REM *** DAVE SMALL 130 REM *** 140 DIM TOP1$(128),BOT1$(128) 150 DIM TOP$(128),BOT$(128) 160 DIM COL$(255) 170 REM *********************** 180 REM * INITIALIZE SCREEN FOR DISP 190 GOSUB 550 200 REM * INITIALIZE COL $ 210 GOSUP 790 220 REM * INITIALIZE ASSEMBLY 230 GOSUB 10000 240 REM *********************** 250 REM * DISPLAY LIST 260 ST=PEEK(560)+Z56XPEEK(561) 270 POKE ST,112+128:REM TOP INK 15) 280 POKE ST+3,13+61+128:REM LMS.DLI 290 FOR Y=6 TO 6+96 STEP 2:REM HI SRS 300 POKE ST+Y, 13+128 310 NEXT Y 320 REM *********************** 330 REM ROTATE COL$ IN HALVES 340 FOR ROT=0 TO 300 STEP 2 350 SANDY=0 360 BOT$=COL$(1,125) 370 TOP$=COL$(126,250) 380 REM ** 390 TOP1$=TOP$(1,120) 400 TOP$=TOP$(121,125) 410 TOP$(6)=TOP1$ 420 TOP$(5,5)=CHR$(ROT) 426 IF ROT>255 THEN TOP$(5,5)=CHR$( ) 430 REM 440 BOT1$=BOT$(1,5) 450 BOT$=BOT$(6) 460 BOT$(121)=BOT1$ 470 REM 480 COL$(1,125)=BOT$ 490 COL$(126)=TOP$ 500 NEXT ROT 510 GOTO 310 530 REM *********************** 540 REM FROM CREATIVE COMPUTING.. 550 GRAPHICS 23:DEG :SETCOLOR 2,1,10:DIM C(3) 560 SETCOLOR 0,0,10 570 SETCOLOR 1,0,6 580 SETCOLOR 2,0,2 590 R=20:COLOR 1:C=1 600 X0=79:Y0=47 610 FOR K=0 TO 3:C(K)=K+1*2:NEXT K 620 FOR K=1 TO 3 630 X=X0+R*COS(360):Y=Y0:PLOT X,Y 640 FOR I=0 TO 5*360 STEP 75 650 X=X0+R*COS(I) I Y-Y0+KXSIN(I) 660 DRAWTO X,Y 670 NEXT I:R=R+12:C=C+I:COLOR C 680 NEXT K 690 Z8=1 700 FOR LOOP=1 TO 50 710 COLOR Z8 720 X8=INT(RND(0)*159)+1 730 Y8=INT(RND(0)*17)+1 740 PLOT X8,Y8 750 Z8=Z8+1:IF Z8=1 THEN Z8=1 760 NEXT LOOP 770 RETURN 780 REM *********************** 790 REM *** INIT COL$ 800 FOR T=1 TO 255 STEP 5 810 COL$(T,T)=CHR$(T) 820 T1=T+80 830 T2=T+160 840 IF T1>255 THEN T1=T1-256 850 IF T2>255 THEN T2=T2-256 860 COL$(T+1,T+1)=CHR$(T1) 870 COL$(T+2,T+2)=CHR$(T2) 880 COL$(T+3,T+3)=CHR$(0) 890 COL$(T+4,T+4)=CHR$(0) 900 NEXT T 910 RETURN