Master Memory Map Part V
by
Robin Sherer
How to read the Memory Map
Beginning users: Read the text that is printed in bold type only. These memory locations will be the easiest for you to use and usually don't involve assembly language.
Advanced users: Read everything! Many areas of memory are not of any practical use, but you can learn a lot about how a computer works by reading the boring parts.
SDMCTL
559 022F
This location is amazing. So many things can be done here that you'll just flip! Maybe not. Anyway, SDMCTL controls something called Direct Memory Access (DMA). Simply put, DMA is the process by which ANTIC, the Atari graphics chip, gets the information from memory it needs to fill in the screen (information for the playfield and for player/missile graphics). Now this process obviously takes time and slows down the 6502 because of that. So what happens if we turn DMA off? Things will run faster. Try it; POKE 559,0 to turn DMA off. Uh-oh, what happened? The screen went blank. But, of course, with no DMA, ANTIC isn't getting the information for the screen; so there's no picture. What good does a computer do without a picture? Well, sometimes you don't need one. For example, if you're doing a lot of calculations, it's more important to get them done quickly than to have an "I'm thinking" message on the screen, and turning off DMA will speed things up by as much as 30% percent! Of course, with a blank screen the user may think that the computer just up and croaked on him; so be sure you give a warning before the lights go off. SDMCTL is a shadow register for DMACTL (54272).
By the way, in case you're still sitting there after the POKE 559,0 with a lifeless computer, just press System Reset or type in POKE 559,34. You can't see the POKE written on the screen, but it will still work when you press Return.
Okay, so we can turn off the screen. Big deal, right? Right, but it's what we can do when we turn the screen back on that counts. SDMCTL lets you make the playfield (the blue screen you PLOT and PRINT onto) wider, narrower or nonexistent. It also lets you turn players and missiles on and off, define how tall you want the players to be and, of course, turn ANTIC on and off.
Let's take a look at a breakdown of SDMCTL and see what does what (Figure 1). To get players and missiles going, see GRACTL [53277] as well.
So, to use SDMCTL, pick the options you want, add their values and POKE away. Note that ANTIC must be turned on if you want a display, and you can only have one type of playfield at a time. While we're on the subject of playfields, you'll probably want to know what "narrow" and "wide" playfields are.
The width of the playfield is measured by something called a "color clock!' A color clock is twice as wide as a pixel in graphics mode 8. That means that a character in graphics mode 0 is four color clocks wide. We'll use graphics mode as an example since you can see the playfield is 160 color clocks wide (40 characters times four color clocks per character). A narrow playfield is only 128 color clocks (32 characters) wide, while a wide playfield has 192 color clocks (48 characters). The television set draws 228 color clocks total (including the black border), but not all of these can be seen. As a matter of fact, not all of the 192 in a wide playfield can be seen either, which makes it good for horizontal scrolling.
Is having a wide or narrow playfield as easy as it sounds? Well, yes and no: getting it on the screen's easy (try POKE 559,35 right now), using it properly isn't. Unfortunately, telling SDMCTL that you want a different size playfield doesn't tell the OS that anything's different. To see what I mean, try POKE 559,35 from graphics mode zero. Now you have 48 characters per line, but the OS still thinks you have 40. Try typing stuff in, and you'll see the problem. There is no way around this problem, which means that you have to set up the screen memory yourself if you want to take advantage of this feature. Sorry.
Double-height players, in case you were wondering, have dots the height of those in graphics mode 7, while regularheight players are the height of graphics mode 8. Despite the way I named the two, double-height players are given to you unless you specify otherwise by using SDMCTL.
SDLSTL
560,561 0230,0231
Another important location, SDLSTL holds the address of the display list. Let's talk display lists.
We already know about screen memory: the memory locations that hold the information that is to be displayed on the screen (see SAVMSC at 88,89). How does the computer know how to interpret this memory though? As we learned in SDMCTL, there is a special chip called ANTIC that takes care of the graphics. ANTIC has a list of commands that tells it how to display the screen memory. Oddly enough, this list is called the "display list." Since the display list is made up of commands, it's actually like a little program. And, since the screen memory has to be redisplayed 60 times a second, this program is a continuous loop, running over and over again. Why does the screen memory have to be redisplayed? The TV set draws a picture by making different parts of the screen glow at different brightnesses. The screen, however, will only glow for a very short period of time. Therefore, in order to get a picture to stay on the screen, the TV has to draw it 60 times a second.
For now, let's pretend that a display list is written just like a BASIC program, only with special commands. Let's see what such a display list would look like:
100 DRAW 8 BLANK SCAN LINES
110 DRAW 8 BLANK SCAN LINES
120 DRAW 8 BLANK SCAN LINES
130 CHARACTER MODE 0 LINE...
140 ... WITH SCREEN MEMORY
STARTING AT [address]
150 CHARACTER MODE 0 LINE
160 CHARACTER MODE 0 LINE
•
•
•
370 CHARACTER MODE 0 LINE
380 GOTO 100 AND WAIT FOR VBLANK
|
FIGURE
1: SDMCTL chart
We start by telling ANTIC to leave the first 24 scan lines blank. Scan lines are the height of a graphics mode 18 line, start before the left edge of the screen and go all the way past the right edge. If you look closely at the screen, you can even see them. We leave 24 lines blank so that we can be sure that all of our picture will be on everyone's screen. TV and monitor screens all act slightly differently; so the blank lines will create a frame that can cover the edges of the screen. These blank lines make up the top of the black border that you can see in graphics mode 0.
Next we want to start our mode 0 lines, so we have a mode 0 line command. ANTIC has to know where the screen memory is before it can start drawing; so we make the first mode 0 command a special one that tells ANTIC that the address of the screen memory will come next. Then, after the screen memory address, we have 23 regular mode 0 commands. Finally, we tell ANTIC to go back to the beginning and start all over again after VBLANK. Remember that VBLANK is the time during which the TV is getting ready to start drawing the picture again. We want to make sure it's ready before ANTIC starts again; so we tell ANTIC to wait until VBLANK is over.
Now that we have a basic understanding, let's look at the specifics. First of all, ANTIC doesn't use line numbers. In a real display list, the line numbers would be memory locations. Secondly, ANTIC has abbreviations for all the commands. And thirdly, there is no thirdly. Let's therefore look at the proper way to write the preceding display list. We'll have it start at location 1000 (decimal), although it would usually be much higher in memory:
1000 BLK 8
1001 BLK 8
1002 BLK 8
1003 CHR 2 LMS
1004 < screen memory low byte >
1005 < screen memory high byte >
1006 CHR 2
1007 CHR 2
•
•
•
1028 CHR 2
1029 JVB 1000
As you can see, this isn't that much different from our original. LMS, by the way, stands for Load Memory Scan and tells ANTIC that the next two bytes will be the address of the beginning of screen memory. Now, the final step is to convert these commands into numbers that we can POKE into memory. There is a unique number assigned to each command, and Figures 2 and 3 give you those numbers. Before you look at that chart, however, let me explain the other commands that you'll see there:
MAP is the same as CHR, except it's used to indicate a graphics mode rather than a character (text) mode.
JMP is like JVB, except it doesn't tell ANTIC to wait for the end of VBLANK. It's needed because of a quirk in ANTIC that says a display list can't cross a 1K boundary. What's a 1K boundary? It's a memory location that's a multiple of 1024. With display lists created by graphics commands, this is no problem. If you're designing your own, however, and you have to cross such a boundary, JMP over it. While we're on the topic of boundaries, you should also be aware that screen memory is not allowed to cross a 4K boundary. If it does, you have to have a second LMS instruction to get past the boundary. Under normal circumstances, however, this only happens in graphics modes 8 through 11 and the OS will take care of it for you.
HSC like LMS, is not really a command but rather a modification to a command. It tells ANTIC that this mode line is to have the capability of fine horizontal scrolling. See HSCROL at 54276.
VSC you guessed it, is another modification that specifies a fine vertical-scrolling capability. See VSCROL (54277).
DLI is the fourth modification, telling ANTIC that there is to be a display list interrupt at the end of this mode line. Pay particular attention to the "end." See VDSLST (512,513) for more details on DLIs.
Now that you'll be able to understand the chart, why don't you go take a quick peek at it.
Run the following program to take a look at the actual graphics mode 0 display list as it is stored in memory:
100
GRAPHICS 0
110 DLIST=PEEK(560)+PEEK(561)*256
120 PRINT PEEK(DLIST)
130 IF PEEK(DLIST)<>65 THEN DLIST=D
LIST+1:GOTO 120
140 PRINT PEEK(DLIST+1)
150 PRINT PEEK(DLIST+2)
160 END
110 DLIST=PEEK(560)+PEEK(561)*256
120 PRINT PEEK(DLIST)
130 IF PEEK(DLIST)<>65 THEN DLIST=D
LIST+1:GOTO 120
140 PRINT PEEK(DLIST+1)
150 PRINT PEEK(DLIST+2)
160 END
Use CTRL-1 to pause the display list. Notice that the last two numbers PRINTed (the address for the JVB) are the same as the values in 560 and 561. If you can't figure out why, drink a couple of cups of coffee and read this whole description all over again. Here is a hint: They tell the computer to go back and use the same display list all over again. If you change the numbers here, the computer will use another display list at the new address, which means you could use several display lists at once.
Load Memory Scan (LMS) is a powerful
tool that has no steadfast rules about its
usage; use your creativity.
tool that has no steadfast rules about its
usage; use your creativity.
We've pretty much covered the standard graphics display lists, but what about custom ones? It should have occurred to you by now that you can write your own display lists, mixing different graphics modes on the screen.
A few words before we move on. What can you use LMS for other than to tell ANTIC where the screen memory is? Nothing! You can, however, tell ANTIC where the screen memory is more than once in the same display list. Why would you want to do that? Well, you have to if you're fine scrolling (see HSCROL and VSCROL). You could also do it to repeat the same line over and over again without wasting memory. LMS is another powerful tool that has no steadfast rules about what to use it for; use your creativity. Here's an example of repeating text. After the program has run, clear the screen and try typing in a line of text.
100
GRAPHICS 0
110 DLIST=PEEK(561)*256+67:POKE 560
,67
120 LOW=PEEK(88)
130 HIGH=PEEK(89)+2
136 POKE 89,HIGH
137 POKE DLIST,112
138 POKE DLIST+1,112
139 POKE DLIST+2,112
140 DLIST=DLIST+3
150 FOR ROW=0 TO 23
160 POKE DLIST,66
170 POKE DLIST+1,LOW
180 POKE DLIST+2,HIGH
190 DLIST=DLIST+3
200 NEXT ROW
210 POKE DLIST,65
220 POKE DLIST+1,PEEK(560)
230 POKE DLIST+2, PEEK(561)
110 DLIST=PEEK(561)*256+67:POKE 560
,67
120 LOW=PEEK(88)
130 HIGH=PEEK(89)+2
136 POKE 89,HIGH
137 POKE DLIST,112
138 POKE DLIST+1,112
139 POKE DLIST+2,112
140 DLIST=DLIST+3
150 FOR ROW=0 TO 23
160 POKE DLIST,66
170 POKE DLIST+1,LOW
180 POKE DLIST+2,HIGH
190 DLIST=DLIST+3
200 NEXT ROW
210 POKE DLIST,65
220 POKE DLIST+1,PEEK(560)
230 POKE DLIST+2, PEEK(561)
What's going on here? Essentially we're rewriting a graphics mode 0 display list so that all the lines have LMSes that point to the same address. We also have to change SAVMSC (88,89), so that the OS knows where our new screen memory is. Why isn't the new screen memory in the same place as the old screen memory? Because our new display list overflows into the old screen memory, that's why.
If you press System Reset, a normal graphics mode 0 screen will appear.
SSKCTL
562 0232
SSKTL is used to control the serial port and is a shadow register for SKCTL (53775). As your state of confusion should indicate to you, it is not really a location for the inexperienced. Look at SKCTL if you are interested; look at the OS manual if you're really interested.
Noname
563 0233
This location is currently unused. Atari reserves the right to use it in future versions of the OS, so don't count on it being safe to use.
LPENH
564 0234
Ever hear of a light pen? The thing that looks like a pen, that you can draw on the screen with and so forth? Well, if you happen to be one of the lucky few who have one, this will tell you what horizontal position on the screen it's pointing to. Neat, huh?
LPENH is a shadow register for PENH (54284).
LPENV
565 0235
This is the vertical position of the light pen on the screen. It's a shadow register for PENV (54285).
Since light pens defy all reason, a few words about them are probably in order here. Firstly, LPENH and LPENV are set when the light pen is pressed to the screen. LPENV gets the value of VCOUNT (54283) when the pen was pressed (VCOUNT gets incremented by one every two scan lines). LPENH, on the other hand, gets a value based on the number of color clocks that have been drawn so far. See SDLSTL for an explanation of a "color clock." Now I'd be more than happy to give you the range of values that LPENH and LPENV will return as you move a light pen about the screen, but unfortunately the values depend on several things. Run the following program to see what the limits are for your computer. Also see STICKO-3 (632-635).
100
GRAPHICS 0
105 POKE 752,1
110 POSITION 2,11
120 PRINT "Light pen horizontal pos
ition = "
130 PRINT " vertical posit
ion = "
140 POSITION 34,11
150 PRINT PEEK(564);" ";
160 POSITION 32,12
170 PRINT PEEK(565);" ";
180 GOTO 140
105 POKE 752,1
110 POSITION 2,11
120 PRINT "Light pen horizontal pos
ition = "
130 PRINT " vertical posit
ion = "
140 POSITION 34,11
150 PRINT PEEK(564);" ";
160 POSITION 32,12
170 PRINT PEEK(565);" ";
180 GOTO 140
You should also note that light pens are not very precise. The values can vary slightly even if you hold it steadily at one point on the screen.
If you're writing a program that uses the light pen, be sure to allow for a little variation in the values. This can be done by "sampling" values. Basically, this means read ten or so values every time you need one, throw out the highest and lowest and average the rest to get a single value.
BRKKEY
566,567 0236,0237
In the "B" version of the OS, this is the vector for the BREAK key interrupt. It is initialized to 59220, which means you will find 84 in location 566 and 231 in location 567. To disable the break key, POKE 143 into 566.
See BRKKEY at location 17 if you want to write your own BREAK key routine and you have the old OS. Also see locations 512 through 535 for more information on interrupt vectors.
Noname
568,569 0238,0239
More "unused" bytes. See the warning at location 563 about such bytes.
Okay, we're going back to I/O now. The next four bytes make up the Command Frame Buffer (CFB), a table that SIO uses when doing serial bus operations. Remember that the serial bus is what information travels back and forth on. It is not designed to be used by you; so you should be reading out of curiosity rather than necessity.
CDEVIC
570 023A
CDEVIC contains the device code.
CCOMND
571 023B
CCOMND contains the command code.
CAUX1
572 023C
CAUX1 contains the command auxiliary byte 1, which comes from DAUX1 at location 778.
CAUX2
573 023D
Finally, CAUX2 contains the command auxiliary byte 2, which SIO gets from DAUX2 at location 779.
TEMP
574 023E
SIO uses TEMP as a TEMPorary storage place (the people who name these things are so clever).
ERRFLG
575 023F
If any error occurred during device I/O, with the exception of a time-out, ERRFLG is set to 255. Otherwise, if everything is okay, it is set to 0.
Also see STATUS at location 48.
DFLAGS
576 0240
When a disk is booted (the computer is turned on with the disk drive on), the first disk "record"-a segment of information that has been recorded on the disk-is read from sector 1 into memory. A sector is a segment of the disk, shaped like a piece of pie. Some of the information from this record is used to continue the boot. The first byte in the record contains several useful flags. It gets stored in DFLAGS.
DBSECT
577 0241
The second byte tells how many sectors are used in the boot file. It gets stored in DBSECT.
BOOTAD
578,579 0242,0243
Finally, because we have to know where to put the file, the third and fourth bytes give the starting address. They get stored in BOOTAD. Once the OS knows BOOTAD, it moves the record it just read in over to the new address and starts loading in the rest of the file, putting each record after the previous one until the whole file is properly in memory.
BOOTAD gets transferred to RAMLO (4,5) which, because it is in page 0, is used to move the file from the sector buffer to its place in memory.
In most cases, the boot file is DOS, and BOOTAD will hold the address 1792.
COLDST
580 0244
COLDST is fun. The OS sets it to one during the power-up process, and then sets it to zero when everything has been properly initialized. If somebody presses System Reset, the OS looks at COLDST to see whether it was in the middle of power-up, when System Reset was pressed. If it was (COLDST equals one), then the turkey who did the pressing messed up the powerup, and the OS has to start all over again. Otherwise, the OS just treats it like a normal reset.
Fun? That's your idea of fun? Hey, let me finish. The OS isn't too smart; COLDST is the only way it knows whether or not it's in the middle of power-up when System Reset is pressed. That means you can set COLDST to one in your program, and if System Reset gets pressed, the computer will act as if somebody just turned the computer on. Your whole program will be erased rather than broken into (usually System Reset will cause the OS to jump to BASIC, where your program can be LISTed or SAVEd).
Use COLDST along with POKMSK (16) and STMCUR (138,139) to totally protect your BASIC program from being looked at or SAVEd. The disk or cassette they're on could still be copied though. Another good use for this trick is to POKE 580,1 and press System Reset instead of using your On/Off switch when you want to load in another program. It saves wear and tear on the computer.
Noname
581 0245
Yet another unused byte for which the warning at location 563 applies.
DSKTIM
582 0246
The disk time-out register. We last saw time-outs at location PTIMOT (28). Well, they're back, this time for the disk drive (PTIMOT was for the printer). DSKTIM holds the time-out value for the FORMAT command. It is supposedly initialized to 160, but I have seen machines that initialize it to 120 and 224, which I suspect has something to do with different versions of the OS. Anyway, regardless of what it's initialized to, the value in DSKTIM is updated after every STATUS request with the value in DVSTAT+2 (748).
You should look at DTIMLO (774) for lots more information on disk time-out, including the exact use for DSKTIM.
LINBUF
583-622 0247-026E
Hey, remember buffers? This is a 40-bytelong buffer used by the screen editor. You see, the screen editor needs a place to temporarily store a line of text when it's moving stuff around on the screen. This is it.
ADDRESS (100,101) is used as a temporary zero-page pointer to LINBUF during the moving process.
In the wonderful
world of Atari graphics,
there are two kinds of things that can appear on the
screen: the playfield and player/missile
graphics.
there are two kinds of things that can appear on the
screen: the playfield and player/missile
graphics.
GPRIOR
623 026F
GPRIOR is used to set priorities and to select GTIA modes.
In the wonderful world of Atari graphics, there are two kinds of things that can appear on the screen. First of all, there is the playfield. The playfield is what you get by PRINTing, PLOTing and DRAWTOing. The playfield is made up of as many as five colors, which are specified by the color registers (as in SETCOLOR color register, color, brightness). Each of these colors represents a different part of the playfield. The one with the same color as color register 0 is called playfield 0 and so forth. The one with the background color (color register 4) is called BAK.
The second type of thing that can appear on the screen is player/missile graphics. We'll be getting more into players and missiles in the CTIA/GTIA chip at location 53248, but for now just be aware that there are four players and four missiles that can appear on the screen at the same time as the playfield.
So, where is all of this getting us? Well, if you have player/missile graphics on the screen, and you also have a playfield, which should be seen when the two are in the same place? In other words, which should have priority over the other? GPRIOR tells ANTIC, the chip that draws the picture, who has the highest priority (i.e., who gets to be seen). Look at the chart in Figure 4.
"PF" means PlayField, "P" means Player. Missiles have the same priority as the player with the same number. Keep in mind that something with a higher priority will appear to move in front of something with a lower priority. Similarly, of course, something with a lower priority will appear to move behind something with a higher priority.
As you probably noticed, only the last four bits of GPRIOR are used to set the priority (make sure only one of those four bits is on). What about the other four? If you set bit 4, then all the missiles will have the same color as playfield 3. That lets you move the missiles together and use them as a fifth player (P4). If you set bit 5, then overlapping player 0 and player 1 will produce a third color in the overlap area. This goes for player 2 and player 3 as well. For machine languagers, or just the curious, the third color is produced by ORing the colors of the two players together.
As long as we're on the subject of overlap colors, if you do set more than one of the last four bits, then in a case where two overlapping objects have the same priority, the overlap area will be black.
In graphics modes 0 and 8, only the color of the text or pixels will be changed if a player or missile flies over them. The brightness will not change.
So now we're left with the seventh and eighth bits. They don't have anything to do with priorities or player/missile graphics. Instead they indicate whether or not a GTIA mode is being used, and if so, which one. They work as shown in Figure 5.
You only need to set these bits if you're writing your own display list. Otherwise the OS will take care of them when you use BASIC to call "GR.9, 10 or 11."
GPRIOR is a shadow register for PRIOR (53275).
|
FIGURE
4: GPRIOR chart
The next 24 locations (624-647) hold information about the joysticks, paddles and light pens.
PADDL0
624 0270
PADDL0 holds the current value of paddle 0 (the left paddle in the leftmost plug in the front of the computer). Paddles can have a value ranging from 0 to 228; the further you turn the paddle clockwise, the higher the value.
Paddles are actually little more than a "potentiometer." Let's look at a potentiometer as though it were a bathroom faucet. The computer sends a value 255 worth of water into the faucet, but the amount that comes out depends on how far open the faucet is. If it's all the way open (the paddle is turned clockwise as far as it will go), then almost all of the water will flow through (228 worth). If it's all the way closed (the paddle is turned counterclockwise as far as it will go), then none of the value will flow through. And that's exactly how a potentiometer works, except the computer is sending electricity into it rather than water (paddles aren't waterproof).
If you design a program that uses the paddles, be careful. Most of the time you won't want them to have a range of 0 to 228. For example, if you're using the paddles to move a player, the player will probably move off the screen. So what can you do to get the range that you want? Let's suppose you want to go from LOW to HIGH. First, do the following:
RANGE=HIGH-LOW+1
EACH=RANGE/228
EACH=RANGE/228
These two lines should come somewhere in your program before you start using the paddles. Then, every time you read the paddle, do the following:
MYVAL=INT(OLDVAL*EACH+.5)+LOW
where OLDVAL is the value of the paddle, and MYVAL is the corresponding number in the range you wanted.
PADDL0 is a shadow register for POT0 at location 53760. Note that the value for the button (trigger) on the paddle can be found at PTRIG0 (636).
The following paddle locations work the same as paddle 0, but you change the number of the paddle (of course). Paddles 0 and 1 plug into the leftmost port (hold) numbered 1 on the front of the Atari computer. Likewise 6 and 7 plug into the rightmost port numbered 4 on the computer.
If you design a program that uses the
paddles, be careful. Most of the time you
won't want them to have a range of 0 to 228.
paddles, be careful. Most of the time you
won't want them to have a range of 0 to 228.
PADDL1
625 0271
The value for paddle 1 and a shadow register for POT1 at 53761.
PADDL2
626 0272
The value for paddle 2 and a shadow register for POT2 at 53762.
PADDL3
627 0273
I'll leave this and the next four for you to figure out. Hint: see the last three locations.
PADDL4
628 0274
PADDL5
629 0275
PADDL6
630 0276
PADDL7
631 0277
STICK0
632 0278
Let's see. PADDL0 was paddle 0, so I wonder what STICK0 is? Could it possibly be joystick 0? Despite all the odds against it, it is. Joystick 0 is the one plugged into the leftmost plug in the front of the computer.
Unlike paddle values, joystick values don't appear at first (or second) to make much sense. Let's take a look at those values (Figure 6).
|
FIGURE
5: GTIA chart
FIGURE 6: Joystick values in decimal
This figure represents the nine possible positions the joystick can be in, along with the value corresponding to each. If you move joystick 0 up, for example, STICK0 will have a value of 14. Now, unless you have some brilliant power of observation that I don't, these values don't seem to make any sense. I mean, does "14" mean "up" to you? Not to me. They must make some kind of sense to the computer, however, so let's take a look at them again (Figure 7), this time in binary, the way the computer sees them.
FIGURE 7: Joystick values in binary
It may not be immediately obvious, but now things make sense. Notice how the first bit (the digit on the right) of each value is only equal to zero when the joystick is up (straight up or diagonally up)? And the second bit is only zero when it's down, the third when it's left and the fourth when it's right. So we get Figure 8.
And that's why the numbers don't make sense when you first look at them.
---0 means "up" ---1 means "not up" --0- means "down" --1- means "not down" -0-- means "left" -1-- means "not left" 0--- means "right" 1--- means "not right" |
FIGURE
8: Joystick bit chart
Here are a couple of machine-language routines to help you make a little more sense out of the joystick values. One looks for vertical movement and will return a zero for up, one for center and two for down. The other looks for horizontal movement and returns a zero for left, one for center and two for right. As you'll see from the following example, these values can prove to be very practical:
100
DIM STICKV$(19):DIM STICKH$(22)
110 FOR CHAR=1 TO 19
120 READ CODE
130 STICKV$(CHAR,CHAR)=CHR$(CODE)
140 NEXT CHAR
150 FOR CHAR=1 TO 22
160 READ CODE
170 STICKH$(CHAR,CHAR)=CHR$(CODE)
180 NEXT CHAR
200 GRAPHICS 0:POKE 752,1
210 PRINT :PRINT "Machine language
joystick example"
220 POSITION 10,4:PRINT "VERTICAL V
ALUE:"
230 POSITION 8,6:PRINT "HORIZONTAL
VALUE:"
240 VERT=USR(ADR(STICKV$),0)-1
250 HORZ=USR(ADR(STICKH$),0)-1
260 POSITION 26,4:PRINT VERT;"
"
270 POSITION 26,6:PRINT HORZ;"
"
280 GOTO 240
1000 DATA 104,104,133,213,104,170,1
89,120,2,41,3
1010 DATA 201,2,240,1,74,133,212,96
2000 DATA 104,104,133,213,104,170,1
89,120,2,74,74
2010 DATA 73,2,201,3,208,2,169,2,13
3,212,96
110 FOR CHAR=1 TO 19
120 READ CODE
130 STICKV$(CHAR,CHAR)=CHR$(CODE)
140 NEXT CHAR
150 FOR CHAR=1 TO 22
160 READ CODE
170 STICKH$(CHAR,CHAR)=CHR$(CODE)
180 NEXT CHAR
200 GRAPHICS 0:POKE 752,1
210 PRINT :PRINT "Machine language
joystick example"
220 POSITION 10,4:PRINT "VERTICAL V
ALUE:"
230 POSITION 8,6:PRINT "HORIZONTAL
VALUE:"
240 VERT=USR(ADR(STICKV$),0)-1
250 HORZ=USR(ADR(STICKH$),0)-1
260 POSITION 26,4:PRINT VERT;"
"
270 POSITION 26,6:PRINT HORZ;"
"
280 GOTO 240
1000 DATA 104,104,133,213,104,170,1
89,120,2,41,3
1010 DATA 201,2,240,1,74,133,212,96
2000 DATA 104,104,133,213,104,170,1
89,120,2,74,74
2010 DATA 73,2,201,3,208,2,169,2,13
3,212,96
If you wanted to read joystick 1 instead of joystick 0, you'd use USR(ADR(STICKV$),1) and USR(ADR (STICKH$),1).
Here's the assembly code that's stored in the DATA statements:
68
STICKV PLA
68 PLA
8505 STA $D5
68 PLA
AA TAX
BD7802 LDA STICK0,X
2903 AND #$03
C902 CMP #$02
F001 BEQ DONE
4A LSR A
85D4 DONE STA $D4
60 RTS
68 STICKH PLA
68 PLA
85D5 STA $D5
68 PLA
AA TAX
BD7802 LDA STICK0,X
4A LSR A
4A LSR A
4902 EOR #$02
C903 CMP #$03
D002 BNE DONE1
A902 LDA #$02
85D4 DONE1 STA $D4
60 RTS
68 PLA
8505 STA $D5
68 PLA
AA TAX
BD7802 LDA STICK0,X
2903 AND #$03
C902 CMP #$02
F001 BEQ DONE
4A LSR A
85D4 DONE STA $D4
60 RTS
68 STICKH PLA
68 PLA
85D5 STA $D5
68 PLA
AA TAX
BD7802 LDA STICK0,X
4A LSR A
4A LSR A
4902 EOR #$02
C903 CMP #$03
D002 BNE DONE1
A902 LDA #$02
85D4 DONE1 STA $D4
60 RTS
STICK0 is a shadow register for the last four bits (the leftmost four) of PORTA at location 54016. It is set to a value other than 15 when a light pen in the leftmost controller jack is pressed on the screen.
STICK1
633 0279
Same as STICK0 except it's a shadow register for the first four bits of PORTA rather than the last two. It's also the value for joystick 1 rather than joystick 0.
|
FIGURE
2: Display list command chart, hex version
|
FIGURE
3: Display list command chart
STICK2
634 027A
Same as STICK1 except it's for joystick 2, and it's also a shadow register for the last four bits of PORTB (54017).
STICK3
635 027B
Joystick 3 (the rightmost one) value and a shadow register for the last four bits of PORTB.
PTRIG0
636 027C
If you press the trigger on paddle zero, PTRIG0 will have a value of zero. If you don't press it, PTRIG0 will have a value of one.
PTRIG0 through PTRIG3 get their values from bits 2, 3, 6 and 7 of PORTA(54016), respectively. Because these are the same bits that tell whether joysticks 1 and 2 are moved to the right or left (see STICK0), you can use the trick in Figure 9.
PTRIG(1)-PTRIG(0)=-1
if joystick zero is moved to the left =0 it joystick zero is in the center =1 If joystick zero is moved to the right |
FIGURE
9: PTRIG chart
The same holds true for PTRIG(3)PTRIG(2) and joystick 1. You can use this trick to make horizontal movement easier to program. Just add the value of the PTRIG difference to your old horizontal position. This saves trying to figure out the joysticks. For the same ease in vertical movement, use the routine given for STICK0.
PTRRG1
637 027D
Same as PTRIG0 but for paddle 1.
PTRIG2
638 027E
Trigger value for paddle 2.
PTRIG3
639 027F
Trigger value for paddle 3.
PTRIG4
640 0280
Trigger value for paddle 4.
PTRIG4 through PTRIG7 get their values from bits 2, 3, 6 and 7 of PORTB (54017), respectively. The same trick for horizontal movement that was described under PTRIG0 can be applied to joystick 2 and joystick 3 using PTRIG4 through PTRIG7.
PTRIG5
641 0281
Trigger value for paddle 5.
PTRIG6
642 0282
Trigger value for paddle 6.
PTRIG7
643 0283
Guess.
STRIG0
644 0284
Well, here we are again at another new, different and challenging name for a location. For the next three as well, actually. All three STRIG locations hold the values for the joystick button, and work exactly the same way as PTRIG (zero means pressed).
The STRIGS are shadow registers for the TRIGS (53264 to 53267).
STRIG1
645 0285
STRIG2
646 0286
STRIG3
647 0287