Chapter Fourteen
Advanced Atari Graphics


No matter how good a BASIC programmer you may be, there are some things that you just can’t do in a BASIC program. BASIC is simply not fat enough to handle such tasks as fine scrolling, high-speed character animation, and player-missile graphics. Assembly language can handle all three of these tasks quite easily, and in this chapter, you’ll see exactly how. Let’s start with fine scrolling.

(figure)

Fine Scrolling

To demonstrate fine scrolling, I’m going to use an expanded version of the title screen program you typed in the preceding chapter. If you’ve saved that program on a disk, you can load it into your computer right now. Then, with a little editing and a few additions, you can modify it until it looks like the listing below. After you’ve modified it, you can save it on a disk, run it, and take a look at it in action. Then I’ll explain how it works, and you’ll have an eye-catching assembly language program that you can use from now on to help you create customized title screens for your own programs.

A Demonstration of Fine Scrolling

FINESCRL.SRC for the Atari Assembler Editor Cartridge

05 ;
10 ;
20 ;HELLO SCREEN (FINE)
30 ;
40  *=$3000
50  JMP INIT
60 ;
70 TCKPTR=$2000
80 FSCPTR=TCKPTR+1
90 ;
0100 SDMCTL=$022F
0110 ;
0120 SDLSTL=$0230
0130 SDLSTH=$0231
0140 ;
0150 COLOR0=$02C4;OS COLOR  REGISTERS
0160 COLOR1=$02C5
0170 COLOR2=$02C6
0180 COLOR3=$02C7
0190 COLOR4=$02C8
0299 ;
0210 HSCROL=$D404
0220 ;
0230 VVBLKI=$0222; OS INTERRUPT VECTOR
0240 SYSVBV=$E45F; INTERRUPT ENABLE VECOTR
0250 ;
0260 SETVBV=$E45C; SET VERTICAL BLANK INTERRUPT (VBI) VECTOR
0270 XITVBV=$E462; EXIT VBI VECTOR
0280 ;
0290 ; DISPLAY LIST DATA
0300 ;
0310 START
0320 LINE1 .SBYTE "   PRESENTING   "
0330 LINE2 .SBYTE "                "
0340  .SBYTE "  the big program  "
0350  .SBYTE "                   "
0360 LINE3 .SBYTE "            By (You"
0370  .SBYTE "r Name)            "
0380 LINE4 .SBYTE "PLEASE STAND BY  "
0390 ;
0400 ; DISPLAY LIST WITH SCROLLING LINE
0410 ;
0420 HLIST ;('HELLO' LIST)
0430  .BYTE $70, $70, $70
0440  .BYTE $70,$70,$70,$70,$70
0450  .BYTE $46
0460  .WORD LINE1
0470 ;NOTE THAT THE LAST BYTE IN THE
0480 ;NEXT LINE IS $57, NOT $47 AS IT
0490 ;WAS IN THE PRECEDING CHAPTER
0500  .BYTE $70,$70,$70,$70,$57
0509 ;THIS THE LINE WE'LL SCROLL
0510 SCROLN ;(THIS IS THE LINE WE'LL SCROLL)
0520  .WORD $00; A BLANK TO BE FILLD IN LATER
0530  .BYTE $70,$42
0540  .WORD LINE3
0550  .BYTE $70,$70,$70,$70,$46
0560  .WORD LINE4
0570  .BYTE $70,$70,$70,$70,$70
0580  .BYTE $41
0590  .WORD HLIST
0600 ;
0610 ;RUN PROGRAM
0620 ;
0630 INIT ;PREPARE TO RUN PROGRAM
0640  LDA COLOR3; SET COLOR REGISTERS
0650  STA COLOR1;
0660  LDA COLOR4;
0670  STA COLOR2;
0680 ;
0690  LDA #0
0700  STA SDMCTL
0710  LDA #HLIST&255
0720  STA SDLSTL
0730  LDA #HLIST/256
0740  STA SDLSTH
0750  LDA #$22
0760  STA SDMCTL
0770 ;
0780  JSR TCKSET; INITIALIZE TICKER ADDRESS
0790 ;
0800  LDA #40; NUMBER OF CHARACTERS IN SCROLL LINE
0810  STA TCKPTR
0820  LDA #8
0830  STA FSCPTR; NUMBER OF CLOR CLOCKS TO FINE SCROLL
0840 ;
0850 ; ENABLE INTERRUPT
0860 ;
0870  LDY #TCKINT&255
0880  LDX #TCKINT/256
0890  LDA #6
0900  JSR SETVBV
0910 ;
0920 ; TICKER INTERRUPT
0930 ;
0940 TCKINT
0950  LDA #SCROLL&255
0960  STA VVBLKI
0970  LDA #SCROLL/256
0980  STA VVBLKI+1
0990 ;
1000 INFIN
1010  JMP INFIN; INFINITE LOOP
1020 ;
1030 SCROLL
1040  LDX FSCPTR; 8 TO START
1050  DEX
1060  STX HSCROL
1070  BNE CONT
1080  LDX #8
1089 ;CONINUE
1090 CONT
1100  STX FSCPTR
1110  CPX #7
1120  BEQ COARSE
1130  JMP SYSVBV
1140 COARSE
1150  LDY TCKPTR; NUMBER OF CHARACTERS TO SCROLL
1160  DEY
1170  BNE SCORSE; LOOP BACK TILL FULL LINE IS SCROLLED
1180  LDY #40
1190  JSR TCKSET; RESET TICKER LINE
1199 ;DO COARSE SCROLL
1200 SCORSE
1210  STY TCKPTR
1220  INC SCROLN; LOW BYTE OF ADDRESS
1230  BNE RETURN
1240  INC SCROLN+1; HIGH BYTE OF ADDRESS
1250 RETURN
1260  JMP SYSVBV
1270 ;
1280 TCKSET
1290  LDA #LINE2&255
1300  STA SCROLN
1310  LDA #LINE2/256
1320  STA SCROLN+1
1330 ENDIT
1340  RTS

Download / View (Assembly source code)

As soon as you’ve typed this program, be sure to save it on a disk immediately. Then you can run it, debug it if necessary, and save it again. Once you have it up and running properly, I think you’ll agree with me that it’s quite a nice display, and it certainly is an example of very smooth scrolling! Now for an explanation of how the program works.

How to Implement Fine Scrolling

The reason fine scrolling works so smoothly is that it has eight times the resolution of coarse scrolling. When coarse scrolling is employed in a program, it causes lines of text to jump across (or up or down) the screen one full character at a time. But when fine scrolling is used, text can be moved around the screen one-eighth of a character at a time. Here’s how that works: Look closely at a text character on your video screen, and you’ll see that it’s made up of a matrix of tiny dots. If you use a magnifying glass, you will be able to see that there are exactly 64 dots in each character. Every character on your screen is eight rows of dots (or scan lines) high, and eight rows of dots (or color clocks) across. And these rows of dots, scan lines and colors, are the increments used in fine scrolling.

To create and implement a fine scrolling routine, several steps are required. First, you must go to your display list and enable fine scrolling by setting certain bits in the LMS instruction that appears before every line you want to scroll. When bit 4 of an LMS instruction is set, the line that follows the LMS instruction can be scrolled horizontally. When bit 5 of an LMS instruction is set, the line that follows the instruction can be scrolled vertically. If both bit 4 and bit 5 of an LMS instruction are set, then the line that follows the instruction can be scrolled both horizontally and vertically.

Take a look at lines 500 through 520 in the program you just typed, and you’ll see that the LMS instruction preceding the line which I’ve labeled SCROLN (the line that scrolls) is $57. Look at the program in its previous incarnation, the version in Chapter 13, in which fine scrolling was not enabled. You will see that this LMS instruction has been changed from $47 to $57.

The number $47, expressed in binary notation, is 0100 0111. As any assembly language programmer can plainly see, bit 4 of that binary number (the fifth bit from the right, since the first bit of a binary number is bit 0), is zero. In other words, bit 0 is not set. When we set bit 4, the number we’re looking at becomes 0101 0111, or $57. Therefore, when horizontal fine scrolling of the line labeled SCROLN is enabled, lines 500 through 520 of our program become:

Now suppose you wanted to scroll SCROLN vertically instead of horizontally. What would you do? Well, you’d simply set bit 5 of the LMS instruction in line 500. Then the $57 that you see in that line would become $67 or, in binary notation, 0110 0111. If you wanted to enable both horizontal and vertical scrolling of the line, you’d simply change the LMS instruction $77 (0111 0111).

Fine scrolling, just like coarse scrolling, can be performed on any number of lines of text on your screen. Just set the proper bit (or bits) in the proper LMS instruction (or instructions), and the desired type of scrolling can be implemented for each selected line. But, you may ask, what if there is no LMS instruction for a line you want to scroll? Well, in that case, you could simply write one. There’s absolutely no reason that a display list can’t have an LMS instruction for every line on the screen. If you want to scroll an entire screen, you must, in fact, put an LMS instruction in front of every line. So far, all we’ve talked about is how to enable fine scrolling. But now that you know how to enable it, how do you actually do it?

Good question.

When fine scrolling of a line is enabled, control of the line is handed over to one of two scrolling registers that reside in your Atari's operating system. If you have authorized a horizontal scroll on a given line of a display, then that line becomes subject to control of a horizontal scroll register, which is abbreviated HSCROL and is situated at memory address $D404. When a vertical scroll has been enabled for a given display list line, then that line becomes subject to the control of a vertical scroll register, or VSCROL, situated at address $D405. If both horizontal and vertical scrolling of a given line are enabled, then that line becomes subject to the control of both the HSCROL and the VSCROL registers. Once control of a line has been turned over to HSCROL, VSCROL or both, then you can implement a fine scroll by simply loading a value into the appropriate scrolling register (or registers). When you load a number into the HSCROL register, every display list line that has been put under the control of that register will be shifted to the right by the number of color clocks loaded into the VSCROL register, and every line for which a vertical scroll has been enabled will be scrolled upward by the number of scan lines you have specified.

Combining Fine Scrolling and Coarse Scrolling

There is one hitch, though. The scrolling registers in your computer are 8-bit registers, and only four of these 8-bits in each register are ever used. That means that fine scrolling can be taken only so far. To work properly, fine scrolling must be combined with coarse scrolling, which can handle as much scrolling data as you can program. Generally speaking, the best way to combine fine scrolling with coarse scrolling is to fine scroll a line or column of characters by seven color clocks or scan lines, and then to reset the appropriate fine scrolling register to its initial value and implement one coarse scroll. Loop through this kind of procedure over and over, and the result will be a smooth fine scroll. You can see how this procedure works by studying and experimenting with the fine scrolling routine in the title screen program we’ve been examining.

Smoothing Out Your Scrolling Action

That’s about all there is to fine scrolling if you don’t mind putting up with a jerk, a jump or a smear every now and then on your video display. If those kinds of messy situations don’t appeal to you, and I’m sure they don’t, then we might as well go ahead and talk about how to make a fine scrolling operation perfect: smooth, smear proof and jerk free.

As you may recall from the preceding chapter, the display on your computer monitor is redrawn by an electron gun 60 times every second, and between each screen refresh there’s a split second total screen blackout that takes place too rapidly for you to see. Well, when you write a fine scrolling routine in assembly language and don’t take a few special precautions, your display may (in fact it virtually always will) smear a bit and jump around a little from time to time. That’s because some of the scrolling action you’ve programmed will sometimes take place while a display is being drawn on your screen by the electron gun inside your video tube. But there is a way to keep that from happening. The folks who designed your Atari have provided you with something called a Vertical Blank Interrupt (VBI) vector, and once you learn how to use that vector, you can perform all kinds of graphics tricks on your computer screen, in real time and without any danger whatsoever of messing up your computer’s screen display.

A vector, as you may know, is a point in your computer’s operating system that contains the address of a specific routine. The primary purpose of a vector is to give you an easy method for implementing an often used routine. When you jump to an OS vector during the course of a program, your program will automatically jump to the OS routine that the vector points to, and you can thus implement that routine without having to write from scratch all of the code that it contains. Vectors can sometimes be used in another way, too. Sometimes you can “steal” a vector; that is, you can change its value so that it will point to some routine you’ve written yourself, rather than the OS routine that it originally pointed to. That means that you can sometimes use a vector as an easy method for controlling the behavior of your computer’s operating system. And that brings us to the point at hand: vertical blank interrupt vectors.

Actually, there are two VBI vectors in your computer, and each one has a corresponding pointer in your Atari’s operating system. One of these vectors is called VVBLKI (“I” for “Immediate”), and the pointer that can be used to access it is situated at memory address $0222. The other VBI pointer is VVBLKD (“D” for Deferred) and resides at memory address $0224.

Every time your Atari starts a vertical blank interrupt, it takes a look at the contents of the VVBLKI pointer. If the program that is being processed does not make use of the VVBLKI pointer, then that pointer will contain nothing but an instruction to jump to a predetermined memory address: specifically, memory address $E45F (which Atari has labeled SYSVBV). Memory address $E45F usually doesn’t contain anything exciting, either. All that it ordinarily contains is an instruction for your computer to continue its normal processing. By stealing the VVBLKI vector, however, you can make it point to any routine you like – usually one you yourself have written. Then, 60 times every second (every time your computer begins its 60 Hertz vertical blank interrupt) it will automatically process the routine whose address you have stored in the VVBLKI pointer. When your routine is finished, your computer will resume its normal processing.

Your computer’s other VBI vector, VVBLKD, also points directly to an exit point unless it has been stolen for a software application. The VVBLKD vector’s normal exit point is memory address $E462, which Atari calls XITVBV, it works just like SYSVBV. It merely terminates your computer’s vertical blank interrupt period and allows your computer to resume normal processing. Once you understand how the VVBLKI and VVBLKD interrupt work, it isn’t difficult to steal them. Here’s all you have to do:

Once those steps are taken, your computer will process your new routine 60 times every second, just before it begins each VBI interrupt if you’ve used the immediate vector, or just before it returns from each VBI interrupt if you’ve used the deferred vector. That makes vector stealing a very valuable technique for writing programs involving high-speed, high-performance processing, such as the processing of routines involving graphics and sound.

At this point, you may be wondering why there are two vectors that you can steal, and what the differences between them are.

Well, the reason is simply that certain user-written routines are best performed at the start of a vertical blank period, while others should not be performed until a VBI has ended. More information on this point can be found in De Re Atari and in The Atari 400/800 Technical Reference Notes.

One More Thing . . .

There’s just one more important fact that you should remember about VBI vector stealing. After you’ve stolen a vector, there’s a small chance that an interrupt will begin after the first byte of the pointer you’re using has been updated, but before the second byte has been changed. If that happens, it could crash your program. But this possibility can be easily avoided. All you have to do is use an operating system routine that the good people who designed your computer thoughtfully provided. This routine is called SETVBV, and it begins at memory address $E45C.

Here’s how to use the SETVBV routine: First, load the 6502 Y register with the low byte of the address of the routine that instructs your computer to begin a vector changing routine. Then load the X register with the high byte of the address. Next, load the accumulator with a 6 for an immediate VBI or a 7 for a deferred VBI. Then do a JSR SETVBV, and your interrupt will be safely enabled. That’s just about the whole story on how to use vertical blank in assembly language fine scrolling programs.

Customizing A Character Set

Your Atari computer has a very fine built-in character set. If you have a late model Atari, it may even have two sets of characters built into its ROM. But how would you like to be able to create your own character sets, including not only letters, numbers and special text symbols, but graphics characters, too?

c14_artist.jpg

Well, you can do that quite easily if you know assembly language. You can do it at lightning speed, too – not at the snail’s pace you may have agonized over if you’ve ever tried to alter a character set using a BASIC program. It’s actually quite easy to design a character set on an Atari computer. As I pointed out earlier in this chapter, each character that your computer prints on your video monitor is made up of an 8 by 8 matrix of dots. This 8 by 8 grid is stored in your computer’s RAM as eight bytes of data. The letter A, for example, is stored in your computer’s memory as a string of binary digits that could be represented in this fashion:

Binary Notation    Hexadecimal Notation    Appearance 

0000 0000                    00
0001 1000                    18                XX
0011 1100                    3C               XXXX
0110 0110                    66              XX  XX
0110 0110                    66              XX  XX
0111 1110                    7E              XXXXXX
0110 0110                    66              XX  XX
0000 0000                    00                      

The primary character set in your computer is composed of 128 letters, each made up of 64 dots that could be arranged in the same 8 by 8 format as the letter “A.” In fact, that is precisely the format in which the letters are arranged when they’re displayed on your computer screen. Since there are 128 characters in a set, and since each character is made up of eight bytes of data, a full character set occupies 1,024 bytes of RAM. Put all of that data together, and you have quite a lengthy table. You also have a table which must start on a 1K boundary because of your computer’s architecture. Character sets can be stored almost anywhere in an Atari computer’s memory, but the address of the character set currently in use is always stored in a specific pointer in the computer’s operating system. That pointer, labeled CHBAS by the engineers who designed your Atari, is situated at memory address $2F4.

To locate a character in your computer, you only have to know two things: the current value of CHBAS, and the ATASCII code for the character you’re seeking. Add the character’s ATASCII code number to the value of CHBASE, and that will be the memory address of the character you’re looking for. If your computer is an Atari 400 or an Atari 800, then its character set is built into ROM and thus, cannot be modified. If you have a later model Atari, your character set has a RAM address and can therefore be accessed somewhat more easily. But, if you want to alter your computer’s built-in character set, you have to do it in a rather indirect way, no matter what kind of Atari you own.

The best way to modify a character set is to copy your computer’s built-in character to some free and easily accessed block of RAM. You can then modify the contents of CHBAS so that is points to the starting address of your own block of characters rather than your computer’s built-in character set. Then you can use either set of characters you like, either the one built into your Atari at the factory or the one you have created on your own.

Once you’ve defined a new character set and stored it in RAM, all you have to do to change your screen display from one character set to another is change the contents of CHBAS. That makes it easy to write routines calling for character animation. All you have to do to animate a character set is draw several different character sets that vary slightly, and then switch back and forth among them by simply changing the contents of the CHBAS pointer. BASIC is too slow to handle a job like that very well, but when you know assembly language, you can animate character sets in real time, at lighting fast speeds. In a moment, I’ll show a program that you can use to custom design your own character sets. The program has two distinct parts. The first part copies the entire Atari character table to a spot in memory selected by the programmer. The second part alters just one character – the character “A”. But the same technique can be used to alter any other character or, if you wish, all of them!

I’d like to make two more observations before you type the next program. First, I’d like to point out that the first half of the program, the part that moves the character set, can be used to move any block of data from any location to any other location in your computer’s RAM. That’s a useful utility, since data often has to be moved from one block of memory to another in assembly language programs. The data moving portion of the program that follows is a particularly good one, since it is designed to move blocks of memory a full page at a time, using 8-bit pointers instead of 16-bit pointers and thus saving a considerable amount of processing time. The second point I’d like to make is that there are ways to create character sets without having to go through the drudgery of drawing character sets on graph paper and then punching them into memory a byte at a time. There are several excellent programs on the market that can help you create your own character sets for Atari computer right on the screen, using a cursor, a set of menus, and keyboard commands. So if you’re interested in computer graphics, it might be to your advantage to take a look at some professionally produced character generator programs.

But that’s enough from me. Here’s your program:

Download / View (Assembly source code)


Notice The "A" Has Been Changed

Player-Missile Graphics

Although animation can be programmed by flipping through alternate character sets, a far easier way to animate characters in an Atari assembly language program is to take advantage of a special graphics feature of Atari computers called player-missile graphics. Player-missile graphics is a technique for programming animation using graphics characters called (not surprisingly) players and missiles. Your Atari computer is equipped with four players, numbered 0 through 3, and four missiles, one for each player. If you write a program that doesn’t call for missile, you can combine your four missiles to form a fifth player. Players and missiles can be used in any graphics mode, and can be drawn and moved around on a video display completely independently of anything else on the screen. They can pass over or under other objects on the screen, and over or under each other. Alternatively, they can be programmed to come to a halt when they run into things, or even to explode upon impact with onscreen objects or with each other!

(figure)

Each of your Atari's four players is 8-bits wide, just like an ordinary graphics character. But players can be much taller than they are wide. Their maximum height is either 128 or 256 bytes high, depending on their vertical resolution. That means a player can be as tall as the full height of your video screen. Each player has its own color register. So by using players, you can add more color to a program than would ordinarily be available. Players are usually single color entities. It is possible, however, to merge two or more players into a multicolored player by placing one player on top of another.

Players can have a vertical resolution of either one or two scan lines. The maximum horizontal resolution of a player is eight pixels, but the width of each horizontal pixel is variable; each pixel can be 8 color colocks, 16 color clocks or 32 color clocks wide. This choice is up to the programmer. The missiles used in player-missile graphics are 2-bit wide spots of light that can be used as bullets, starts, or other small graphics objects. Or, as previously mentioned, they can be combined to form a fifth full-size player.

Players are made up of grids of dots, just as standard text characters are. They can therefore be disigned on graph paper, in the same way that ordingary text characters are created. Before you start blocking out a player on graph paper, however, it might be a good idea to remember what a player looks like on the screen when all of its bits are filled in. When a player is completely filled in, it looks like a ribbon extending from the top of a video screen to the bottom. You won't neeed nearly all of that height for most programming needs. before you start drawing a player, it's usally a good idea to "erase" that entire ribbion by filling it in with zeros. The whole ribbon will thus become invisible. Then you can draw your player in exactly the same way you'd draw a conventional text character, by filling in its shape with "on" bits, or binary ones. When you've finished drawing your players in this way, you can store them almost anywhere in RAM. You can tell your computer when your players and missiles are by simply storing the starting address of the RAM in which they appear in an OS pointer called PMBASE. The address of PMBASE is $D407.

Since player and missiles are graphics objects, it is considered good programming practice to store them in high RAM, just below your computer's screen display. Atari's in-house programmers, who generally know what they're talking about, recommend that you store your player-missile display RAM about 2K bytes below the top of your Atari computer's memory. Once you've figured out where your player-missile RAM is going to be stored, and consequently, what address PMBASE will point to, you can start storing the data for your players and missiles right into RAM. Here's a chart showing where the RAM for each player and missile will start, in respect to the address stored in PMBASE:

SINGLE-LINE RESOLUTION
OFFSET FROM PMBASE   CONTENTS
-----------------------------
+     0 -  767       Unused
+   768 - 1023       Missiles
+  1024 - 1279       Player 0
+  1280 - 1535       Player 1
+  1536 - 1791       Player 2
+  1792 - 2047       Player 3
+  2046              End of P/M RAM

Must start on a 2K address boundary. 
DOUBLE-LINE RESOLUTION
OFFSET FROM PMBASE   CONTENTS
-----------------------------
+     0 -  383       Unused
+   384 -  511       Missiles
+   512 -  639       Player 0
+   640 -  767       Player 1
+   768 -  895       Player 2
+   896 - 1023       Player 3
+  1023              End of P/M RAM

Must start on a 1K address boundary. 

When your players and missiles are drawn and stored in RAM, it's faily simple to move them around on your screen. In your computer's operating system there's a set of memory registers that are used to keep track of the horizontal positions of all players and missiles. These registers are labeled HPOSP0 through HPOSP3 (for players) and HPOSM0 through HPOSM3 (for missiles). The addresses of these registers are:

HORIZONTAL
REGISTER FOR:     LABEL     ADDRESS

Player 0          HPOSP0    D000
Player 1          HPOSP1    D001
Player 2          HPOSP2    D002
Player 3          HPOSP3    D003

Missile 0         HPOSM0    D004
Missile 1         HPOSM1    D005
Missile 2         HPOSM2    D006
Missile 3         HPOSM3    D007

When you w ant to move a player or a missile from one horizontal position to another, all you have to do is change the value of the appropriate horizontal register.

Changing the vertical position of a player or a missile is a little more difficult. To move a player up or down, you have to "erase" the player from the vertical ribbon on which it appears by filling that space in with zeros. Then you have to redraw it in a position higher or lower in the block of RAM that makes up the ribbon.

The utility program below, the final program in this book, is a demonstration of how to use player-missile graphics. As a special bonus, it will also show you how to use a joystick in assembly language programs.

The joystick reading portion of the program begins with a set of instructions setting bit 2of a register called PACTL (for "Port A ConTroL") located at memory address $D302. When bit 2 of PACTL is set, the reading of game controllers is enabled. The direction switches of a joystick plugged into port A can then be read, in much the same way as they are read in BASIC programs. When you type this program in and run it, you'll be able to move a little pink heart around on your screen using a joystick controller. When the heart disappears from the screen in any direction, keep your joystick switch pressed, and it will soon "wrap around" and reappear on the opposite edge of the screen, just where you would expect it to, moving in the same direction.

This program uses vertical blank interrupts, just like the smooth scrolling routine presented at the beginning of this chapter. As you'll see when you type the program and run it, assembly language is the best possible language to use when you're working with player-missile graphics. If you've ever worked with player-missile graphics using BASIC, you'll soon see that PM/G action is much faster and much smoother when it's programmed in assembly language.

10 ;
20 ; PLAYER-MISSLE GRAPHICS ROUTINE
30 ;
50  *=$5000
60  JMP START
70 ;
80 RAMTOP=$6A ;TOP OF RAM PTR
90 VVBLKD=$0224 ;INTERRUPT RTN
0100 SDMCTL=$022F ;DMA CNT. SHADOW
0110 SDLSTL=$0230 ;SDLST, LOW BYTE
0120 STICK0=$0278
0130 PCOLR0=$02C0 ;PLAYER COLOR
0140 COLOR2=$02C6 ;BKG COLOR
0150 ;
0160 HPOSP0=$D000 ;PLAYER HORZ PSN
0170 GRACTL=$D01D
0180 PACTL=$D302 ;JS PORT CNTRL
0190 PMBASE=$D407 ;PM BASE ADR
0200 SETVBV=$E45C ;ENABLE INTRPT
0210 XITVBV =$E462 ;EXIT INTERRUPT
0220 ;
0230 HRZPTR=$0600 ;HORIZ PSN PTR
0240 VRTPTR=HRZPTR+1 ;VRT PSN PTR
0250 OURBAS=VRTPTR+1 ;OUR PMBASE
0260 TABSIZ=OURBAS+2 ;TABLE SIZE
0270 FILVAL=TABSIZ+2 ;BLKFIL VALUE
0280 ;
0290 TABPTR=$B0 ;TABLE ADDR PTR
0300 TABADR=TABPTR+2 ;TABLE ADDRESS
0310 ;
0320 PLBOFS=512 ;PLAYER BAS OFFS
0330 PLTOFS=640 ;PLAYER TOP OFFS
0340 ;
0350 SHAPE .BYTE $00,$6C,$FE,$FE,$7C,$38,$10,$00
0360 ;
0370 START
0380 ;
0390 ;CLEAR SCREEN
0400 ;
0410  LDA #0
0420  STA FILVAL
0430  LDA SDLSTL
0440  STA TABPTR
0450  LDA SDLSTL+1
0460  STA TABPTR+1
0470  LDA #960&255 ;BYTES PER SCRN
0480  STA TABSIZ
0490  LDA #960/256
0500  STA TABSIZ+1
0510  JSR BLKFIL
0520 ;
0530 ;DEFINE PMG VARIABLES
0540 ;
0550  LDA #0
0560  STA COLOR2 ;BLACK BKG
0570  LDA #$58
0580  STA PCOLR0 ;PINK PLAYER
0590 ;
0600  LDA #100 ;SET HORIZ PSN
0610  STA HRZPTR
0620  STA HPOSP0
0630 ;
0640  LDA #48 ;SET VERT PSN
0650  STA VRTPTR
0660 ;
0670  LDA #0 ;CLEAR OURBASE
0680  STA OURBAS
0690  STA OURBAS+1
0700 ;
0710  SEC
0720  LDA RAMTOP
0730  SBC #8
0740  STA PMBASE ;BASE=RAMTOP-2K
0750  STA OURBAS+1 ;SAVE BASE ADR
0760 ;
0770  LDA #46
0780  STA SDMCTL ;ENABLE PM DMA
0790 ;
0800  LDA #3
0810  STA GRACTL ;ENABLE PM DSPLY
0820 ;
0830 ;FILL PM RAM W/ZEROS TO CLEAR
0840 ;
0850  CLC
0860  LDA OURBAS
0870  ADC #PLBOFS&255
0880  STA TABADR
0890  STA TABPTR
0900  LDA OURBAS+1
0910  ADC #PLBOFS/256
0920  STA TABADR+1
0930  STA TABPTR+1
0940 ;
0950  SEC
0960  LDA #PLTOFS&255
0970  SBC #PLBOFS&255
0980  STA TABSIZ
0990  LDA #PLTOFS/256
1000  SBC #PLBOFS/256
1010  STA TABSIZ+1
1020 ;
1030  LDA #0
1040  STA FILVAL
1050  JSR BLKFIL
1060 ;
1070 ;DEFINE PLAYER
1080 ;
1090 PLAYER
1100 ;
1110 ;DRAW PLAYER
1120 ;
1130  JSR DRAWPL
1140 ;
1150 ;ENABLE INTERRUPT
1160 ;
1170  LDY #INTRPT&255
1180  LDX #INTRPT/256
1190  LDA #7
1200  JSR SETVBV
1210 ;
1220 INTRPT
1230  LDA #RDSTIK&255
1240  STA VVBLKD
1250  LDA #RDSTIK/256
1260  STA VVBLKD+1
1270 ;
1280 ;INFINITE LOOP
1290 ;
1300 INFIN
1310  JMP INFIN
1320 ;
1330 ;READ JOYSTICK
1340 ;
1350 RDSTIK
1360  LDA #4
1370  ORA PACTL ;SET BIT #5
1380 ;
1390  LDA STICK0
1400  CMP #$F ;JS STRAIGHT UP?
1410  BEQ RETURN ;YES, NO ACTION
1420 ;
1430 TRYAGN
1440  CMP #$07 ;RIGHT MOVE
1450  BNE TRYAG2
1454  STA EYEOFS
1460  LDX HRZPTR
1470  INX
1480  STX HRZPTR
1490  STX HPOSP0
1500  JMP RETURN
1510 ;
1520 TRYAG2
1530  CMP #$0B ;LEFT MOVE
1540  BNE TRYAG3
1550 ;
1560  LDX HRZPTR
1570  DEX
1580  STX HRZPTR
1590  STX HPOSP0
1600  JMP RETURN
1610 ;
1620 TRYAG3
1630  CMP #$0D ;DOWN MOVE
1640  BNE TRYAG4
1650 ;
1660  INC VRTPTR
1670  JSR DRAWPL
1680  JMP RETURN
1690 ;
1700 TRYAG4
1710  CMP #$0E ;UP MOVE
1720  BNE RETURN
1730 ;
1740  DEC VRTPTR
1750  JSR DRAWPL
1760  JMP RETURN
1770 ;
1780 RETURN
1790  JMP XITVBV
1800 ;
1810 ;BLOCK FILL ROUTINE
1820 ;
1830 BLKFIL
1840 ;
1850 ;DO FULL PAGES FIRST
1860 ;
1870  LDA FILVAL
1880  LDX TABSIZ+1
1890  BEQ PARTPG
1900  LDY #0
1910 FULLPG
1920  STA (TABPTR), Y
1930  INY
1940  BNE FULLPG
1950  INC TABPTR+1
1960  DEX
1970  BNE FULLPG
1980 ;
1990 ;DO REMAINING PARTIAL PAGE
2000 ;
2010 PARTPG
2020  LDX TABSIZ
2030  BEQ FINI
2040  LDY #0
2050 ;
2060 PARTLP
2070  STA (TABPTR),Y
2080  INY
2090  DEX
2100  BNE PARTLP
2110 ;
2120 FINI
2130  RTS
2140 ;
2150 DRAWPL
2160  PHA ;SAVE ACC VALUE
2170  CLC
2180  LDA TABADR
2190  ADC VRTPTR
2200  STA TABPTR
2210  LDA TABADR+1
2220  ADC #0
2230  STA TABPTR+1
2240 ;
2250  LDA #0
2260 FILLPL
2270  LDA SHAPE,Y
2280  STA (TABPTR), Y
2290  INY
2300  CPY #8
2310  BCC FILLPL ;REPEAT TILL DONE
2320  PLA ;RESTORE ACC VAL
2330  RTS

Download / View (Assembly source code)

Not The End

This concludes this traveler’s guide to the fascinating world of Atari assembly language. If you have typed and saved all of the programs in this book, you now have a fairly extensive library of assembly language routines that you can (no doubt) improve upon, and use in your own programs. If you have absorbed the material that surrounds the routines in this volume, you now know just about all you need to know to start writing some pretty sophisticated programs in assembly language.

I have just one more suggestion. If you’re interested in doing more programming in Atari assembly language - and I certainly hope you are - then there are two other books which you should definitely own. They are (in case you haven’t already guessed) De Re Atari and The Atari 400/800 Technical Reference Notes both published by Atari. With those two books, and the one you have just finished, you should be able to do just about anything you want to do from now on in Atari assembly language.

(figure)


Return to Table of Contents | Previous Chapter | Next Chapter